diff --git a/BinaryObjectScanner.Test/BinaryObjectScanner.Test.csproj b/BinaryObjectScanner.Test/BinaryObjectScanner.Test.csproj index 6ebf3c78..445d5d26 100644 --- a/BinaryObjectScanner.Test/BinaryObjectScanner.Test.csproj +++ b/BinaryObjectScanner.Test/BinaryObjectScanner.Test.csproj @@ -17,9 +17,9 @@ all - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/BinaryObjectScanner.Test/FactoryTests.cs b/BinaryObjectScanner.Test/FactoryTests.cs index 3771c927..65daae96 100644 --- a/BinaryObjectScanner.Test/FactoryTests.cs +++ b/BinaryObjectScanner.Test/FactoryTests.cs @@ -65,7 +65,7 @@ namespace BinaryObjectScanner.Test //WrapperType.CIA, //WrapperType.Executable, WrapperType.GCF, - WrapperType.GZIP, + WrapperType.GZip, WrapperType.InstallShieldArchiveV3, WrapperType.InstallShieldCAB, WrapperType.LZKWAJ, diff --git a/BinaryObjectScanner.Test/FileType/GZIPTests.cs b/BinaryObjectScanner.Test/FileType/GZIPTests.cs index 4fafa72c..393b50e0 100644 --- a/BinaryObjectScanner.Test/FileType/GZIPTests.cs +++ b/BinaryObjectScanner.Test/FileType/GZIPTests.cs @@ -11,7 +11,7 @@ namespace BinaryObjectScanner.Test.FileType { string file = string.Empty; string outDir = string.Empty; - var extractable = new GZIP(); + var extractable = new GZip(); bool actual = extractable.Extract(file, outDir, includeDebug: false); Assert.False(actual); @@ -23,7 +23,7 @@ namespace BinaryObjectScanner.Test.FileType Stream? stream = null; string file = string.Empty; string outDir = string.Empty; - var extractable = new GZIP(); + var extractable = new GZip(); bool actual = extractable.Extract(stream, file, outDir, includeDebug: false); Assert.False(actual); @@ -35,7 +35,7 @@ namespace BinaryObjectScanner.Test.FileType Stream? stream = new MemoryStream(); string file = string.Empty; string outDir = string.Empty; - var extractable = new GZIP(); + var extractable = new GZip(); bool actual = extractable.Extract(stream, file, outDir, includeDebug: false); Assert.False(actual); diff --git a/BinaryObjectScanner.Test/FileType/PKZIPTests.cs b/BinaryObjectScanner.Test/FileType/PKZIPTests.cs index 6b3454ed..4699ef23 100644 --- a/BinaryObjectScanner.Test/FileType/PKZIPTests.cs +++ b/BinaryObjectScanner.Test/FileType/PKZIPTests.cs @@ -17,17 +17,6 @@ namespace BinaryObjectScanner.Test.FileType Assert.False(actual); } - [Fact] - public void ExtractFile_LookForHeader_EmptyString_False() - { - string file = string.Empty; - string outDir = string.Empty; - var extractable = new PKZIP(); - - bool actual = extractable.Extract(file, outDir, lookForHeader: true, includeDebug: false); - Assert.False(actual); - } - [Fact] public void ExtractStream_Null_False() { @@ -40,18 +29,6 @@ namespace BinaryObjectScanner.Test.FileType Assert.False(actual); } - [Fact] - public void ExtractStream_LookForHeader_Null_False() - { - Stream? stream = null; - string file = string.Empty; - string outDir = string.Empty; - var extractable = new PKZIP(); - - bool actual = extractable.Extract(stream, file, outDir, lookForHeader: true, includeDebug: false); - Assert.False(actual); - } - [Fact] public void ExtractStream_Empty_False() { @@ -63,17 +40,5 @@ namespace BinaryObjectScanner.Test.FileType bool actual = extractable.Extract(stream, file, outDir, includeDebug: false); Assert.False(actual); } - - [Fact] - public void ExtractStream_LookForHeader_Empty_False() - { - Stream? stream = new MemoryStream(); - string file = string.Empty; - string outDir = string.Empty; - var extractable = new PKZIP(); - - bool actual = extractable.Extract(stream, file, outDir, lookForHeader: true, includeDebug: false); - Assert.False(actual); - } } } diff --git a/BinaryObjectScanner.Test/FileType/QuantumTests.cs b/BinaryObjectScanner.Test/FileType/QuantumTests.cs index 3a20c349..9e7d0d2a 100644 --- a/BinaryObjectScanner.Test/FileType/QuantumTests.cs +++ b/BinaryObjectScanner.Test/FileType/QuantumTests.cs @@ -40,29 +40,5 @@ namespace BinaryObjectScanner.Test.FileType bool actual = extractable.Extract(stream, file, outDir, includeDebug: false); Assert.False(actual); } - - [Fact] - public void ExtractAll_EmptyModel_False() - { - var model = new SabreTools.Models.Quantum.Archive(); - var data = new MemoryStream(); - var item = new SabreTools.Serialization.Wrappers.Quantum(model, data); - string outputDirectory = string.Empty; - - bool actual = Quantum.ExtractAll(item, outputDirectory); - Assert.False(actual); - } - - [Fact] - public void ExtractFile_EmptyModel_False() - { - var model = new SabreTools.Models.Quantum.Archive(); - var data = new MemoryStream(); - var item = new SabreTools.Serialization.Wrappers.Quantum(model, data); - string outputDirectory = string.Empty; - - bool actual = Quantum.ExtractFile(item, 0, outputDirectory); - Assert.False(actual); - } } } diff --git a/BinaryObjectScanner.Test/FileType/RARTests.cs b/BinaryObjectScanner.Test/FileType/RARTests.cs index 3473547f..6c94e7ae 100644 --- a/BinaryObjectScanner.Test/FileType/RARTests.cs +++ b/BinaryObjectScanner.Test/FileType/RARTests.cs @@ -17,17 +17,6 @@ namespace BinaryObjectScanner.Test.FileType Assert.False(actual); } - [Fact] - public void ExtractFile_LookForHeader_EmptyString_False() - { - string file = string.Empty; - string outDir = string.Empty; - var extractable = new RAR(); - - bool actual = extractable.Extract(file, outDir, lookForHeader: true, includeDebug: false); - Assert.False(actual); - } - [Fact] public void ExtractStream_Null_False() { @@ -40,18 +29,6 @@ namespace BinaryObjectScanner.Test.FileType Assert.False(actual); } - [Fact] - public void ExtractStream_LookForHeader_Null_False() - { - Stream? stream = null; - string file = string.Empty; - string outDir = string.Empty; - var extractable = new RAR(); - - bool actual = extractable.Extract(stream, file, outDir, lookForHeader: true, includeDebug: false); - Assert.False(actual); - } - [Fact] public void ExtractStream_Empty_False() { @@ -63,17 +40,5 @@ namespace BinaryObjectScanner.Test.FileType bool actual = extractable.Extract(stream, file, outDir, includeDebug: false); Assert.False(actual); } - - [Fact] - public void ExtractStream_LookForHeader_Empty_False() - { - Stream? stream = new MemoryStream(); - string file = string.Empty; - string outDir = string.Empty; - var extractable = new RAR(); - - bool actual = extractable.Extract(stream, file, outDir, lookForHeader: true, includeDebug: false); - Assert.False(actual); - } } } diff --git a/BinaryObjectScanner.Test/FileType/SevenZipTests.cs b/BinaryObjectScanner.Test/FileType/SevenZipTests.cs index acaec87d..4b7692db 100644 --- a/BinaryObjectScanner.Test/FileType/SevenZipTests.cs +++ b/BinaryObjectScanner.Test/FileType/SevenZipTests.cs @@ -17,17 +17,6 @@ namespace BinaryObjectScanner.Test.FileType Assert.False(actual); } - [Fact] - public void ExtractFile_LookForHeader_EmptyString_False() - { - string file = string.Empty; - string outDir = string.Empty; - var extractable = new SevenZip(); - - bool actual = extractable.Extract(file, outDir, lookForHeader: true, includeDebug: false); - Assert.False(actual); - } - [Fact] public void ExtractStream_Null_False() { @@ -40,18 +29,6 @@ namespace BinaryObjectScanner.Test.FileType Assert.False(actual); } - [Fact] - public void ExtractStream_LookForHeader_Null_False() - { - Stream? stream = null; - string file = string.Empty; - string outDir = string.Empty; - var extractable = new SevenZip(); - - bool actual = extractable.Extract(stream, file, outDir, lookForHeader: true, includeDebug: false); - Assert.False(actual); - } - [Fact] public void ExtractStream_Empty_False() { @@ -63,17 +40,5 @@ namespace BinaryObjectScanner.Test.FileType bool actual = extractable.Extract(stream, file, outDir, includeDebug: false); Assert.False(actual); } - - [Fact] - public void ExtractStream_LookForHeader_Empty_False() - { - Stream? stream = new MemoryStream(); - string file = string.Empty; - string outDir = string.Empty; - var extractable = new SevenZip(); - - bool actual = extractable.Extract(stream, file, outDir, lookForHeader: true, includeDebug: false); - Assert.False(actual); - } } } diff --git a/BinaryObjectScanner.Test/Packer/ASPackTests.cs b/BinaryObjectScanner.Test/Packer/ASPackTests.cs index 530569eb..c1f8c3f8 100644 --- a/BinaryObjectScanner.Test/Packer/ASPackTests.cs +++ b/BinaryObjectScanner.Test/Packer/ASPackTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new ASPack(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/AdvancedInstallerTests.cs b/BinaryObjectScanner.Test/Packer/AdvancedInstallerTests.cs index f3e496b9..6d44f0da 100644 --- a/BinaryObjectScanner.Test/Packer/AdvancedInstallerTests.cs +++ b/BinaryObjectScanner.Test/Packer/AdvancedInstallerTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new AdvancedInstaller(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/AutoPlayMediaStudioTests.cs b/BinaryObjectScanner.Test/Packer/AutoPlayMediaStudioTests.cs index 54ae6b53..c6c8e65e 100644 --- a/BinaryObjectScanner.Test/Packer/AutoPlayMediaStudioTests.cs +++ b/BinaryObjectScanner.Test/Packer/AutoPlayMediaStudioTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new AutoPlayMediaStudio(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/CExeTests.cs b/BinaryObjectScanner.Test/Packer/CExeTests.cs index 978fcc77..8200cdc3 100644 --- a/BinaryObjectScanner.Test/Packer/CExeTests.cs +++ b/BinaryObjectScanner.Test/Packer/CExeTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new CExe(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/CrunchTests.cs b/BinaryObjectScanner.Test/Packer/CrunchTests.cs index 2870f1dd..f1178148 100644 --- a/BinaryObjectScanner.Test/Packer/CrunchTests.cs +++ b/BinaryObjectScanner.Test/Packer/CrunchTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new Crunch(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/DotFuscatorTests.cs b/BinaryObjectScanner.Test/Packer/DotFuscatorTests.cs index fbd3f21d..8c4644a9 100644 --- a/BinaryObjectScanner.Test/Packer/DotFuscatorTests.cs +++ b/BinaryObjectScanner.Test/Packer/DotFuscatorTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new DotFuscator(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/DotNetReactorTests.cs b/BinaryObjectScanner.Test/Packer/DotNetReactorTests.cs index d6331ba7..592a9baf 100644 --- a/BinaryObjectScanner.Test/Packer/DotNetReactorTests.cs +++ b/BinaryObjectScanner.Test/Packer/DotNetReactorTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new DotNetReactor(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/EXEStealthTests.cs b/BinaryObjectScanner.Test/Packer/EXEStealthTests.cs index 679bec35..21ea13a7 100644 --- a/BinaryObjectScanner.Test/Packer/EXEStealthTests.cs +++ b/BinaryObjectScanner.Test/Packer/EXEStealthTests.cs @@ -29,19 +29,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new EXEStealth(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/EmbeddedArchiveTests.cs b/BinaryObjectScanner.Test/Packer/EmbeddedArchiveTests.cs deleted file mode 100644 index 9cc6c441..00000000 --- a/BinaryObjectScanner.Test/Packer/EmbeddedArchiveTests.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.IO; -using BinaryObjectScanner.Packer; -using Xunit; - -namespace BinaryObjectScanner.Test.Packer -{ - public class EmbeddedArchiveTests - { - [Fact] - public void CheckPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - - var checker = new EmbeddedArchive(); - string? actual = checker.CheckExecutable(file, pex, includeDebug: false); - Assert.Null(actual); - } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new EmbeddedArchive(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } - } -} \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/EmbeddedExecutableTests.cs b/BinaryObjectScanner.Test/Packer/EmbeddedExecutableTests.cs deleted file mode 100644 index 30ed4701..00000000 --- a/BinaryObjectScanner.Test/Packer/EmbeddedExecutableTests.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.IO; -using BinaryObjectScanner.Packer; -using Xunit; - -namespace BinaryObjectScanner.Test.Packer -{ - public class EmbeddedExecutableTests - { - [Fact] - public void CheckPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - - var checker = new EmbeddedExecutable(); - string? actual = checker.CheckExecutable(file, pex, includeDebug: false); - Assert.Null(actual); - } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new EmbeddedExecutable(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } - } -} \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/EmbeddedFileTests.cs b/BinaryObjectScanner.Test/Packer/EmbeddedFileTests.cs new file mode 100644 index 00000000..c090e4aa --- /dev/null +++ b/BinaryObjectScanner.Test/Packer/EmbeddedFileTests.cs @@ -0,0 +1,22 @@ +using System.IO; +using BinaryObjectScanner.Packer; +using Xunit; + +namespace BinaryObjectScanner.Test.Packer +{ + public class EmbeddedFileTests + { + [Fact] + public void CheckPortableExecutableTest() + { + string file = "filename"; + SabreTools.Models.PortableExecutable.Executable model = new(); + Stream source = new MemoryStream(); + SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); + + var checker = new EmbeddedFile(); + string? actual = checker.CheckExecutable(file, pex, includeDebug: false); + Assert.Null(actual); + } + } +} \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/GenteeInstallerTests.cs b/BinaryObjectScanner.Test/Packer/GenteeInstallerTests.cs index c43d3859..8c626341 100644 --- a/BinaryObjectScanner.Test/Packer/GenteeInstallerTests.cs +++ b/BinaryObjectScanner.Test/Packer/GenteeInstallerTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new GenteeInstaller(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/HyperTechCrackProofTests.cs b/BinaryObjectScanner.Test/Packer/HyperTechCrackProofTests.cs index d3ccea37..2a4fd90e 100644 --- a/BinaryObjectScanner.Test/Packer/HyperTechCrackProofTests.cs +++ b/BinaryObjectScanner.Test/Packer/HyperTechCrackProofTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new HyperTechCrackProof(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/InnoSetupTests.cs b/BinaryObjectScanner.Test/Packer/InnoSetupTests.cs index ced3f575..26e10a1e 100644 --- a/BinaryObjectScanner.Test/Packer/InnoSetupTests.cs +++ b/BinaryObjectScanner.Test/Packer/InnoSetupTests.cs @@ -31,33 +31,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractNewExecutableTest() - { - string file = "filename"; - SabreTools.Models.NewExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.NewExecutable nex = new(model, source); - string outputDir = string.Empty; - - var checker = new InnoSetup(); - bool actual = checker.Extract(file, nex, outputDir, includeDebug: false); - Assert.False(actual); - } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new InnoSetup(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/InstallAnywhereTests.cs b/BinaryObjectScanner.Test/Packer/InstallAnywhereTests.cs index 11b50e7c..6bddd2f3 100644 --- a/BinaryObjectScanner.Test/Packer/InstallAnywhereTests.cs +++ b/BinaryObjectScanner.Test/Packer/InstallAnywhereTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new InstallAnywhere(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/InstallerVISETests.cs b/BinaryObjectScanner.Test/Packer/InstallerVISETests.cs index e1a1d579..bffb71ec 100644 --- a/BinaryObjectScanner.Test/Packer/InstallerVISETests.cs +++ b/BinaryObjectScanner.Test/Packer/InstallerVISETests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new InstallerVISE(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/IntelInstallationFrameworkTests.cs b/BinaryObjectScanner.Test/Packer/IntelInstallationFrameworkTests.cs index 7d5c3822..332f6ff6 100644 --- a/BinaryObjectScanner.Test/Packer/IntelInstallationFrameworkTests.cs +++ b/BinaryObjectScanner.Test/Packer/IntelInstallationFrameworkTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new IntelInstallationFramework(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/MicrosoftCABSFXTests.cs b/BinaryObjectScanner.Test/Packer/MicrosoftCABSFXTests.cs index 98548316..4f08778a 100644 --- a/BinaryObjectScanner.Test/Packer/MicrosoftCABSFXTests.cs +++ b/BinaryObjectScanner.Test/Packer/MicrosoftCABSFXTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new MicrosoftCABSFX(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/NSISTests.cs b/BinaryObjectScanner.Test/Packer/NSISTests.cs index 1675967b..6a4d1b4f 100644 --- a/BinaryObjectScanner.Test/Packer/NSISTests.cs +++ b/BinaryObjectScanner.Test/Packer/NSISTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new NSIS(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/NeoLiteTests.cs b/BinaryObjectScanner.Test/Packer/NeoLiteTests.cs index ea524ba6..72d6f515 100644 --- a/BinaryObjectScanner.Test/Packer/NeoLiteTests.cs +++ b/BinaryObjectScanner.Test/Packer/NeoLiteTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new NeoLite(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/PECompactTests.cs b/BinaryObjectScanner.Test/Packer/PECompactTests.cs index 4ccdb38a..e00b1a8d 100644 --- a/BinaryObjectScanner.Test/Packer/PECompactTests.cs +++ b/BinaryObjectScanner.Test/Packer/PECompactTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new PECompact(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/PEtiteTests.cs b/BinaryObjectScanner.Test/Packer/PEtiteTests.cs index 6acf7dc0..ca9b8797 100644 --- a/BinaryObjectScanner.Test/Packer/PEtiteTests.cs +++ b/BinaryObjectScanner.Test/Packer/PEtiteTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new PEtite(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/SetupFactoryTests.cs b/BinaryObjectScanner.Test/Packer/SetupFactoryTests.cs index f413163d..4eb1ad60 100644 --- a/BinaryObjectScanner.Test/Packer/SetupFactoryTests.cs +++ b/BinaryObjectScanner.Test/Packer/SetupFactoryTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new SetupFactory(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/SevenZipSFXTests.cs b/BinaryObjectScanner.Test/Packer/SevenZipSFXTests.cs index 81298db9..bbd2f96a 100644 --- a/BinaryObjectScanner.Test/Packer/SevenZipSFXTests.cs +++ b/BinaryObjectScanner.Test/Packer/SevenZipSFXTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new SevenZipSFX(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/ShrinkerTests.cs b/BinaryObjectScanner.Test/Packer/ShrinkerTests.cs index 98ecc9dd..0753d8fd 100644 --- a/BinaryObjectScanner.Test/Packer/ShrinkerTests.cs +++ b/BinaryObjectScanner.Test/Packer/ShrinkerTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new Shrinker(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/UPXTests.cs b/BinaryObjectScanner.Test/Packer/UPXTests.cs index ed654638..d8e3c1ae 100644 --- a/BinaryObjectScanner.Test/Packer/UPXTests.cs +++ b/BinaryObjectScanner.Test/Packer/UPXTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new UPX(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/WinRARSFXTests.cs b/BinaryObjectScanner.Test/Packer/WinRARSFXTests.cs index 2987a9c0..5c746586 100644 --- a/BinaryObjectScanner.Test/Packer/WinRARSFXTests.cs +++ b/BinaryObjectScanner.Test/Packer/WinRARSFXTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new WinRARSFX(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/WinZipSFXTests.cs b/BinaryObjectScanner.Test/Packer/WinZipSFXTests.cs index c521e2c3..c14ba844 100644 --- a/BinaryObjectScanner.Test/Packer/WinZipSFXTests.cs +++ b/BinaryObjectScanner.Test/Packer/WinZipSFXTests.cs @@ -31,33 +31,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractNewExecutableTest() - { - string file = "filename"; - SabreTools.Models.NewExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.NewExecutable nex = new(model, source); - string outputDir = string.Empty; - - var checker = new WinZipSFX(); - bool actual = checker.Extract(file, nex, outputDir, includeDebug: false); - Assert.False(actual); - } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new WinZipSFX(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Packer/WiseInstallerTests.cs b/BinaryObjectScanner.Test/Packer/WiseInstallerTests.cs index add51b15..543bcf31 100644 --- a/BinaryObjectScanner.Test/Packer/WiseInstallerTests.cs +++ b/BinaryObjectScanner.Test/Packer/WiseInstallerTests.cs @@ -31,33 +31,5 @@ namespace BinaryObjectScanner.Test.Packer string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractNewExecutableTest() - { - string file = "filename"; - SabreTools.Models.NewExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.NewExecutable nex = new(model, source); - string outputDir = string.Empty; - - var checker = new WiseInstaller(); - bool actual = checker.Extract(file, nex, outputDir, includeDebug: false); - Assert.False(actual); - } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new WiseInstaller(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner.Test/Protection/ArmadilloTests.cs b/BinaryObjectScanner.Test/Protection/ArmadilloTests.cs index fb4addb2..22458bc0 100644 --- a/BinaryObjectScanner.Test/Protection/ArmadilloTests.cs +++ b/BinaryObjectScanner.Test/Protection/ArmadilloTests.cs @@ -18,19 +18,5 @@ namespace BinaryObjectScanner.Test.Protection string? actual = checker.CheckExecutable(file, pex, includeDebug: false); Assert.Null(actual); } - - [Fact] - public void ExtractPortableExecutableTest() - { - string file = "filename"; - SabreTools.Models.PortableExecutable.Executable model = new(); - Stream source = new MemoryStream(); - SabreTools.Serialization.Wrappers.PortableExecutable pex = new(model, source); - string outputDir = string.Empty; - - var checker = new Armadillo(); - bool actual = checker.Extract(file, pex, outputDir, includeDebug: false); - Assert.False(actual); - } } } \ No newline at end of file diff --git a/BinaryObjectScanner/BinaryObjectScanner.csproj b/BinaryObjectScanner/BinaryObjectScanner.csproj index 59cd8c04..0bce1d1e 100644 --- a/BinaryObjectScanner/BinaryObjectScanner.csproj +++ b/BinaryObjectScanner/BinaryObjectScanner.csproj @@ -28,56 +28,18 @@ MIT - - - $(DefineConstants);WINX86 - - - $(DefineConstants);WINX64 - - - - - - $(DefaultItemExcludes); - **\AssemblyInfo.cs; - _EXTERNAL\stormlibsharp\lib\**; - _EXTERNAL\stormlibsharp\src\TestConsole\** - - - - - - - $(DefaultItemExcludes); - _EXTERNAL\** - - - - - - - %(Identity) - true - - - - - - - - - - - - - + + + + + + + \ No newline at end of file diff --git a/BinaryObjectScanner/Factory.cs b/BinaryObjectScanner/Factory.cs index deb996c3..f314f6f0 100644 --- a/BinaryObjectScanner/Factory.cs +++ b/BinaryObjectScanner/Factory.cs @@ -40,8 +40,9 @@ namespace BinaryObjectScanner WrapperType.BZip2 => new FileType.BZip2(), WrapperType.CFB => new FileType.CFB(), //WrapperType.CIA => new FileType.CIA(), + WrapperType.Executable => new FileType.Executable(), WrapperType.GCF => new FileType.GCF(), - WrapperType.GZIP => new FileType.GZIP(), + WrapperType.GZip => new FileType.GZip(), WrapperType.InstallShieldArchiveV3 => new FileType.InstallShieldArchiveV3(), WrapperType.InstallShieldCAB => new FileType.InstallShieldCAB(), WrapperType.LZKWAJ => new FileType.LZKWAJ(), diff --git a/BinaryObjectScanner/FileType/BFPK.cs b/BinaryObjectScanner/FileType/BFPK.cs index 1f084fda..fed0da92 100644 --- a/BinaryObjectScanner/FileType/BFPK.cs +++ b/BinaryObjectScanner/FileType/BFPK.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Extract all files Directory.CreateDirectory(outDir); - bfpk.ExtractAll(outDir); + bfpk.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/BSP.cs b/BinaryObjectScanner/FileType/BSP.cs index eed89306..3223f50d 100644 --- a/BinaryObjectScanner/FileType/BSP.cs +++ b/BinaryObjectScanner/FileType/BSP.cs @@ -30,7 +30,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - bsp.ExtractAllLumps(outDir); + bsp.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/BZip2.cs b/BinaryObjectScanner/FileType/BZip2.cs index fd5b98ae..014f8c10 100644 --- a/BinaryObjectScanner/FileType/BZip2.cs +++ b/BinaryObjectScanner/FileType/BZip2.cs @@ -1,7 +1,5 @@ -using System; -using System.IO; +using System.IO; using BinaryObjectScanner.Interfaces; -using SabreTools.Compression.BZip2; namespace BinaryObjectScanner.FileType { @@ -23,39 +21,16 @@ namespace BinaryObjectScanner.FileType /// public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) { - if (stream == null || !stream.CanRead) + // Create the wrapper + var bzip = SabreTools.Serialization.Wrappers.BZip2.Create(stream); + if (bzip == null) return false; - try - { - // Try opening the stream - using var bz2File = new BZip2InputStream(stream, true); + // Loop through and extract all files + Directory.CreateDirectory(outDir); + bzip.Extract(outDir, includeDebug); - // Ensure directory separators are consistent - string filename = Guid.NewGuid().ToString(); - if (Path.DirectorySeparatorChar == '\\') - filename = filename.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - filename = filename.Replace('\\', '/'); - - // Ensure the full output directory exists - filename = Path.Combine(outDir, filename); - var directoryName = Path.GetDirectoryName(filename); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - // Extract the file - using FileStream fs = File.OpenWrite(filename); - bz2File.CopyTo(fs); - fs.Flush(); - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } + return true; } } } diff --git a/BinaryObjectScanner/FileType/CFB.cs b/BinaryObjectScanner/FileType/CFB.cs index 81991c46..ec47f880 100644 --- a/BinaryObjectScanner/FileType/CFB.cs +++ b/BinaryObjectScanner/FileType/CFB.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; +using System.IO; using BinaryObjectScanner.Interfaces; -using SabreTools.IO.Extensions; -using SabreTools.Models.CFB; -using static SabreTools.Models.CFB.Constants; namespace BinaryObjectScanner.FileType { @@ -27,725 +21,16 @@ namespace BinaryObjectScanner.FileType /// public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) { - // Get a wrapper for the CFB - var model = Deserialize(stream); - if (model == null) - return false; - - var cfb = new SabreTools.Serialization.Wrappers.CFB(model, stream); - if (cfb?.Model == null) + // Create the wrapper + var cfb = SabreTools.Serialization.Wrappers.CFB.Create(stream); + if (cfb == null) return false; // Loop through and extract all files Directory.CreateDirectory(outDir); - ExtractAll(cfb, outDir, includeDebug); + cfb.Extract(outDir, includeDebug); return true; } - - #region REMOVE WHEN SERIALIZATION UPDATED - - /// - /// Extract all files from the CFB to an output directory - /// - /// Output directory to write to - /// True to include debug data, false otherwise - /// True if all files extracted, false otherwise - private static bool ExtractAll(SabreTools.Serialization.Wrappers.CFB? cfb, string outputDirectory, bool includeDebug) - { - // If we have no files - if (cfb?.Model?.DirectoryEntries == null || cfb.Model.DirectoryEntries.Length == 0) - return false; - - // Loop through and extract all directory entries to the output - bool allExtracted = true; - for (int i = 0; i < cfb.Model.DirectoryEntries.Length; i++) - { - allExtracted &= ExtractEntry(cfb, i, outputDirectory, includeDebug); - } - - return allExtracted; - } - - /// - /// Extract a file from the CFB to an output directory by index - /// - /// Entry index to extract - /// Output directory to write to - /// True to include debug data, false otherwise - /// True if the file extracted, false otherwise - private static bool ExtractEntry(SabreTools.Serialization.Wrappers.CFB cfb, int index, string outputDirectory, bool includeDebug) - { - // If we have no entries - if (cfb?.Model?.DirectoryEntries == null || cfb.Model.DirectoryEntries.Length == 0) - return false; - - // If we have an invalid index - if (index < 0 || index >= cfb.Model.DirectoryEntries.Length) - return false; - - // Get the entry information - var entry = cfb.Model.DirectoryEntries[index]; - if (entry == null) - return false; - - // Only try to extract stream objects - if (entry.ObjectType != ObjectType.StreamObject) - return true; - - // Get the entry data - byte[]? data = GetDirectoryEntryData(cfb, entry); - if (data == null) - return false; - - // If we have an invalid output directory - if (string.IsNullOrEmpty(outputDirectory)) - return false; - - // Ensure the output filename is trimmed - string filename = entry.Name ?? $"entry{index}"; - byte[] nameBytes = Encoding.UTF8.GetBytes(filename); - if (nameBytes[0] == 0xe4 && nameBytes[1] == 0xa1 && nameBytes[2] == 0x80) - filename = Encoding.UTF8.GetString(nameBytes, 3, nameBytes.Length - 3); - - foreach (char c in Path.GetInvalidFileNameChars()) - { - filename = filename.Replace(c, '_'); - } - - // Ensure directory separators are consistent - if (Path.DirectorySeparatorChar == '\\') - filename = filename.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - filename = filename.Replace('\\', '/'); - - // Ensure the full output directory exists - filename = Path.Combine(outputDirectory, filename); - var directoryName = Path.GetDirectoryName(filename); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - // Try to write the data - try - { - // Open the output file for writing - using FileStream fs = File.OpenWrite(filename); - fs.Write(data); - fs.Flush(); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } - - return true; - } - - /// - /// Read the entry data for a single directory entry, if possible - /// - /// Entry to try to retrieve data for - /// Byte array representing the entry data on success, null otherwise - private static byte[]? GetDirectoryEntryData(SabreTools.Serialization.Wrappers.CFB cfb, DirectoryEntry entry) - { - // If the CFB is invalid - if (cfb.Model?.Header == null) - return null; - - // Only try to extract stream objects - if (entry.ObjectType != ObjectType.StreamObject) - return null; - - // Determine which FAT is being used - bool miniFat = entry.StreamSize < cfb.Model.Header.MiniStreamCutoffSize; - - // Get the chain data - var chain = miniFat - ? GetMiniFATSectorChainData(cfb, (SectorNumber)entry.StartingSectorLocation) - : GetFATSectorChainData(cfb, (SectorNumber)entry.StartingSectorLocation); - if (chain == null) - return null; - - // Return only the proper amount of data - byte[] data = new byte[entry.StreamSize]; - Array.Copy(chain, 0, data, 0, (int)Math.Min(chain.Length, (long)entry.StreamSize)); - return data; - } - - /// Adapted from LibMSI - private static string? DecodeStreamName(string input) - { - if (input == null) - return null; - - int count = 0; - byte[] inputBytes = Encoding.UTF8.GetBytes(input); - int p = 0; // inputBytes[0] - - byte[] output = new byte[inputBytes.Length + 1]; - int q = 0; // output[0] - while (p < inputBytes.Length && inputBytes[p] != 0) - { - int ch = inputBytes[p]; - if ((ch == 0xe3 && inputBytes[p + 1] >= 0xa0) || (ch == 0xe4 && inputBytes[p + 1] < 0xa0)) - { - // UTF-8 encoding of 0x3800..0x47ff. - output[q++] = (byte)Mime2Utf(inputBytes[p + 2] & 0x7f); - output[q++] = (byte)Mime2Utf(inputBytes[p + 1] ^ 0xa0); - p += 3; - count += 2; - continue; - } - - if (ch == 0xe4 && inputBytes[p + 1] == 0xa0) - { - // UTF-8 encoding of 0x4800..0x483f. - output[q++] = (byte)Mime2Utf(inputBytes[p + 2] & 0x7f); - p += 3; - count++; - continue; - } - - output[q++] = inputBytes[p++]; - if (ch >= 0xc1) - output[q++] = inputBytes[p++]; - if (ch >= 0xe0) - output[q++] = inputBytes[p++]; - if (ch >= 0xf0) - output[q++] = inputBytes[p++]; - - count++; - } - - output[q] = 0; - return Encoding.UTF8.GetString(output); - } - - /// Adapted from LibMSI - private static int Mime2Utf(int x) - { - if (x < 10) - return x + '0'; - if (x < (10 + 26)) - return x - 10 + 'A'; - if (x < (10 + 26 + 26)) - return x - 10 - 26 + 'a'; - if (x == (10 + 26 + 26)) - return '.'; - return '_'; - } - - /// - private static Binary? Deserialize(Stream? data) - { - // If the data is invalid - if (data == null || !data.CanRead) - return null; - - try - { - // Create a new binary to fill - var binary = new Binary(); - - #region Header - - // Try to parse the file header - var fileHeader = ParseFileHeader(data); - if (fileHeader?.Signature != SignatureUInt64) - return null; - if (fileHeader.ByteOrder != 0xFFFE) - return null; - if (fileHeader.MajorVersion == 3 && fileHeader.SectorShift != 0x0009) - return null; - else if (fileHeader.MajorVersion == 4 && fileHeader.SectorShift != 0x000C) - return null; - if (fileHeader.MajorVersion == 3 && fileHeader.NumberOfDirectorySectors != 0) - return null; - if (fileHeader.MiniStreamCutoffSize != 0x00001000) - return null; - - // Set the file header - binary.Header = fileHeader; - - #endregion - - #region DIFAT Sector Numbers - - // Create a DIFAT sector table - var difatSectors = new List(); - - // Add the sectors from the header - if (fileHeader.DIFAT != null) - difatSectors.AddRange(fileHeader.DIFAT); - - // Loop through and add the DIFAT sectors - var currentSector = (SectorNumber?)fileHeader.FirstDIFATSectorLocation; - for (int i = 0; i < fileHeader.NumberOfDIFATSectors; i++) - { - // If we have an unreadable sector - if (currentSector > SectorNumber.MAXREGSECT) - break; - - // Get the new next sector information - long sectorOffset = (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift)); - if (sectorOffset < 0 || sectorOffset >= data.Length) - return null; - - // Seek to the next sector - data.Seek(sectorOffset, SeekOrigin.Begin); - - // Try to parse the sectors - var sectorNumbers = ParseSectorNumbers(data, fileHeader.SectorShift); - if (sectorNumbers == null) - return null; - - // Add all but the last sector number that was parsed - for (int j = 0; j < sectorNumbers.Length - 1; j++) - { - difatSectors.Add(sectorNumbers[j]); - } - - // Get the next sector from the final sector number - currentSector = sectorNumbers[sectorNumbers.Length - 1]; - } - - // Assign the DIFAT sectors table - binary.DIFATSectorNumbers = [.. difatSectors]; - - #endregion - - #region FAT Sector Numbers - - // Create a FAT sector table - var fatSectors = new List(); - - // Loop through and add the FAT sectors - for (int i = 0; i < fileHeader.NumberOfFATSectors; i++) - { - // Get the next sector from the DIFAT - currentSector = binary.DIFATSectorNumbers[i]; - - // If we have an unreadable sector - if (currentSector > SectorNumber.MAXREGSECT) - break; - - // Get the new next sector information - long sectorOffset = (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift)); - if (sectorOffset < 0 || sectorOffset >= data.Length) - return null; - - // Seek to the next sector - data.Seek(sectorOffset, SeekOrigin.Begin); - - // Try to parse the sectors - var sectorNumbers = ParseSectorNumbers(data, fileHeader.SectorShift); - if (sectorNumbers == null) - return null; - - // Add the sector shifts - fatSectors.AddRange(sectorNumbers); - } - - // Assign the FAT sectors table - binary.FATSectorNumbers = [.. fatSectors]; - - #endregion - - #region Mini FAT Sector Numbers - - // Create a mini FAT sector table - var miniFatSectors = new List(); - - // Loop through and add the mini FAT sectors - currentSector = (SectorNumber)fileHeader.FirstMiniFATSectorLocation; - for (int i = 0; i < fileHeader.NumberOfMiniFATSectors; i++) - { - // If we have an unreadable sector - if (currentSector > SectorNumber.MAXREGSECT) - break; - - // Get the new next sector information - long sectorOffset = (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift)); - if (sectorOffset < 0 || sectorOffset >= data.Length) - return null; - - // Seek to the next sector - data.Seek(sectorOffset, SeekOrigin.Begin); - - // Try to parse the sectors - var sectorNumbers = ParseSectorNumbers(data, fileHeader.SectorShift); - if (sectorNumbers == null) - return null; - - // Add the sector shifts - miniFatSectors.AddRange(sectorNumbers); - - // Get the next sector from the FAT - currentSector = binary.FATSectorNumbers[(int)currentSector]; - } - - // Assign the mini FAT sectors table - binary.MiniFATSectorNumbers = [.. miniFatSectors]; - - #endregion - - #region Directory Entries - - // Create a directory sector table - var directorySectors = new List(); - - // Get the number of directory sectors - uint directorySectorCount = 0; - switch (fileHeader.MajorVersion) - { - case 3: - directorySectorCount = int.MaxValue; - break; - case 4: - directorySectorCount = fileHeader.NumberOfDirectorySectors; - break; - } - - // Loop through and add the directory sectors - currentSector = (SectorNumber)fileHeader.FirstDirectorySectorLocation; - for (int i = 0; i < directorySectorCount; i++) - { - // If we have an end of chain - if (currentSector == SectorNumber.ENDOFCHAIN) - break; - - // If we have an unusable sector for a version 3 file - if (directorySectorCount == int.MaxValue && currentSector > SectorNumber.MAXREGSECT) - break; - - // Get the new next sector information - long sectorOffset = (long)((long)(currentSector + 1) * Math.Pow(2, fileHeader.SectorShift)); - if (sectorOffset < 0 || sectorOffset >= data.Length) - return null; - - // Seek to the next sector - data.Seek(sectorOffset, SeekOrigin.Begin); - - // Try to parse the sectors - var directoryEntries = ParseDirectoryEntries(data, fileHeader.SectorShift, fileHeader.MajorVersion); - if (directoryEntries == null) - return null; - - // Add the sector shifts - directorySectors.AddRange(directoryEntries); - - // Get the next sector from the FAT - currentSector = binary.FATSectorNumbers[(int)currentSector]; - } - - // Assign the Directory sectors table - binary.DirectoryEntries = [.. directorySectors]; - - #endregion - - return binary; - } - catch - { - // Ignore the actual error - return null; - } - } - - /// - /// Parse a Stream into a DirectoryEntry - /// - /// Stream to parse - /// Filled DirectoryEntry on success, null on error - private static DirectoryEntry ParseDirectoryEntry(Stream data) - { - var obj = new DirectoryEntry(); - - byte[] name = data.ReadBytes(64); - obj.Name = DecodeStreamName(Encoding.Unicode.GetString(name))?.TrimEnd('\0'); - obj.NameLength = data.ReadUInt16LittleEndian(); - obj.ObjectType = (ObjectType)data.ReadByteValue(); - obj.ColorFlag = (ColorFlag)data.ReadByteValue(); - obj.LeftSiblingID = (StreamID)data.ReadUInt32LittleEndian(); - obj.RightSiblingID = (StreamID)data.ReadUInt32LittleEndian(); - obj.ChildID = (StreamID)data.ReadUInt32LittleEndian(); - obj.CLSID = data.ReadGuid(); - obj.StateBits = data.ReadUInt32LittleEndian(); - obj.CreationTime = data.ReadUInt64LittleEndian(); - obj.ModifiedTime = data.ReadUInt64LittleEndian(); - obj.StartingSectorLocation = data.ReadUInt32LittleEndian(); - obj.StreamSize = data.ReadUInt64LittleEndian(); - - return obj; - } - - /// - /// Parse a Stream into a FileHeader - /// - /// Stream to parse - /// Filled FileHeader on success, null on error - private static FileHeader ParseFileHeader(Stream data) - { - var obj = new FileHeader(); - - obj.Signature = data.ReadUInt64LittleEndian(); - obj.CLSID = data.ReadGuid(); - obj.MinorVersion = data.ReadUInt16LittleEndian(); - obj.MajorVersion = data.ReadUInt16LittleEndian(); - obj.ByteOrder = data.ReadUInt16LittleEndian(); - obj.SectorShift = data.ReadUInt16LittleEndian(); - obj.MiniSectorShift = data.ReadUInt16LittleEndian(); - obj.Reserved = data.ReadBytes(6); - obj.NumberOfDirectorySectors = data.ReadUInt32LittleEndian(); - obj.NumberOfFATSectors = data.ReadUInt32LittleEndian(); - obj.FirstDirectorySectorLocation = data.ReadUInt32LittleEndian(); - obj.TransactionSignatureNumber = data.ReadUInt32LittleEndian(); - obj.MiniStreamCutoffSize = data.ReadUInt32LittleEndian(); - obj.FirstMiniFATSectorLocation = data.ReadUInt32LittleEndian(); - obj.NumberOfMiniFATSectors = data.ReadUInt32LittleEndian(); - obj.FirstDIFATSectorLocation = data.ReadUInt32LittleEndian(); - obj.NumberOfDIFATSectors = data.ReadUInt32LittleEndian(); - obj.DIFAT = new SectorNumber[109]; - for (int i = 0; i < 109; i++) - { - obj.DIFAT[i] = (SectorNumber)data.ReadUInt32LittleEndian(); - } - - // Skip rest of sector for version 4 - if (obj.MajorVersion == 4) - _ = data.ReadBytes(3584); - - return obj; - } - - /// - /// Parse a Stream into a sector full of sector numbers - /// - /// Stream to parse - /// Sector shift from the header - /// Filled sector full of sector numbers on success, null on error - private static SectorNumber[] ParseSectorNumbers(Stream data, ushort sectorShift) - { - int sectorCount = (int)(Math.Pow(2, sectorShift) / sizeof(uint)); - var sectorNumbers = new SectorNumber[sectorCount]; - - for (int i = 0; i < sectorNumbers.Length; i++) - { - sectorNumbers[i] = (SectorNumber)data.ReadUInt32LittleEndian(); - } - - return sectorNumbers; - } - - /// - /// Parse a Stream into a sector full of directory entries - /// - /// Stream to parse - /// Sector shift from the header - /// Major version from the header - /// Filled sector full of directory entries on success, null on error - private static DirectoryEntry[]? ParseDirectoryEntries(Stream data, ushort sectorShift, ushort majorVersion) - { - // - int directoryEntrySize = 128; - - int dirsPerSector = (int)(Math.Pow(2, sectorShift) / directoryEntrySize); - var directoryEntries = new DirectoryEntry[dirsPerSector]; - - for (int i = 0; i < directoryEntries.Length; i++) - { - var directoryEntry = ParseDirectoryEntry(data); - - // Handle version 3 entries - if (majorVersion == 3) - directoryEntry.StreamSize &= 0x00000000FFFFFFFF; - - directoryEntries[i] = directoryEntry; - } - - return directoryEntries; - } - - /// - /// Get the ordered FAT sector chain for a given starting sector - /// - /// Initial FAT sector - /// Ordered list of sector numbers, null on error - private static List? GetFATSectorChain(SabreTools.Serialization.Wrappers.CFB cfb, SectorNumber? startingSector) - { - // If we have an invalid sector - if (startingSector == null || startingSector < 0 || cfb.Model.FATSectorNumbers == null || (long)startingSector >= cfb.Model.FATSectorNumbers.Length) - return null; - - // Setup the returned list - var sectors = new List { startingSector.Value }; - - var lastSector = startingSector; - while (true) - { - if (lastSector == null) - break; - - // Get the next sector from the lookup table - var nextSector = cfb.Model.FATSectorNumbers[(uint)lastSector!.Value]; - - // If we have an invalid sector - if (nextSector >= SectorNumber.MAXREGSECT) - break; - - // Add the next sector to the list and replace the last sector - sectors.Add(nextSector); - lastSector = nextSector; - } - - return sectors; - } - - /// - /// Get the data for the FAT sector chain starting at a given starting sector - /// - /// Initial FAT sector - /// Ordered list of sector numbers, null on error - private static byte[]? GetFATSectorChainData(SabreTools.Serialization.Wrappers.CFB cfb, SectorNumber startingSector) - { - // Get the sector chain first - var sectorChain = GetFATSectorChain(cfb, startingSector); - if (sectorChain == null) - return null; - - // Sequentially read the sectors - var data = new List(); - for (int i = 0; i < sectorChain.Count; i++) - { - // Try to get the sector data offset - int sectorDataOffset = (int)FATSectorToFileOffset(cfb, sectorChain[i]); - if (sectorDataOffset < 0 || sectorDataOffset >= cfb.GetEndOfFile()) - return null; - - // Try to read the sector data - var sectorData = cfb.ReadFromDataSource(sectorDataOffset, (int)cfb.SectorSize); - if (sectorData == null) - return null; - - // Add the sector data to the output - data.AddRange(sectorData); - } - - return [.. data]; - } - - /// - /// Convert a FAT sector value to a byte offset - /// - /// Sector to convert - /// File offset in bytes, -1 on error - private static long FATSectorToFileOffset(SabreTools.Serialization.Wrappers.CFB cfb, SectorNumber? sector) - { - // If we have an invalid sector number - if (sector == null || sector > SectorNumber.MAXREGSECT) - return -1; - - // Convert based on the sector shift value - return (long)(sector + 1) * cfb.SectorSize; - } - - /// - /// Get the ordered Mini FAT sector chain for a given starting sector - /// - /// Initial Mini FAT sector - /// Ordered list of sector numbers, null on error - private static List? GetMiniFATSectorChain(SabreTools.Serialization.Wrappers.CFB cfb, SectorNumber? startingSector) - { - // If we have an invalid sector - if (startingSector == null || startingSector < 0 || cfb.Model.MiniFATSectorNumbers == null || (long)startingSector >= cfb.Model.MiniFATSectorNumbers.Length) - return null; - - // Setup the returned list - var sectors = new List { startingSector.Value }; - - var lastSector = startingSector; - while (true) - { - if (lastSector == null) - break; - - // Get the next sector from the lookup table - var nextSector = cfb.Model.MiniFATSectorNumbers[(uint)lastSector!.Value]; - - // If we have an invalid sector - if (nextSector >= SectorNumber.MAXREGSECT) - break; - - // Add the next sector to the list and replace the last sector - sectors.Add(nextSector); - lastSector = nextSector; - } - - return sectors; - } - - /// - /// Get the data for the Mini FAT sector chain starting at a given starting sector - /// - /// Initial Mini FAT sector - /// Ordered list of sector numbers, null on error - private static byte[]? GetMiniFATSectorChainData(SabreTools.Serialization.Wrappers.CFB cfb, SectorNumber startingSector) - { - // Ignore invalid data - if (cfb.Model?.Header == null || cfb.Model.DirectoryEntries == null || cfb.Model.DirectoryEntries.Length == 0) - return null; - - // Get the mini stream offset - uint miniStreamSectorLocation = cfb.Model.DirectoryEntries[0].StartingSectorLocation; - - // Get the mini stream data - var miniStreamData = GetFATSectorChainData(cfb, (SectorNumber)miniStreamSectorLocation); - if (miniStreamData == null) - return null; - - // Get the sector chain - var sectorChain = GetMiniFATSectorChain(cfb, startingSector); - if (sectorChain == null) - return null; - - // Sequentially read the sectors - var data = new List(); - for (int i = 0; i < sectorChain.Count; i++) - { - // Try to get the mini stream data offset - int streamDataOffset = (int)MiniFATSectorToMiniStreamOffset(cfb, sectorChain[i]); - if (streamDataOffset < 0 || streamDataOffset > miniStreamData.Length) - return null; - - // Try to read the sector data - var sectorData = miniStreamData.ReadBytes(ref streamDataOffset, (int)cfb.MiniSectorSize); - if (sectorData == null) - return null; - - // Add the sector data to the output - data.AddRange(sectorData); - } - - return [.. data]; - } - - /// - /// Convert a Mini FAT sector value to a byte offset - /// - /// Sector to convert - /// Stream offset in bytes, -1 on error - /// Offset is within the mini stream, not the full file - private static long MiniFATSectorToMiniStreamOffset(SabreTools.Serialization.Wrappers.CFB cfb, SectorNumber? sector) - { - // If we have an invalid sector number - if (sector == null || sector > SectorNumber.MAXREGSECT) - return -1; - - // Get the mini stream location - return (long)sector * cfb.MiniSectorSize; - } - - #endregion } } diff --git a/BinaryObjectScanner/FileType/Executable.cs b/BinaryObjectScanner/FileType/Executable.cs index 8b866d89..a80ef802 100644 --- a/BinaryObjectScanner/FileType/Executable.cs +++ b/BinaryObjectScanner/FileType/Executable.cs @@ -4,7 +4,6 @@ using System.IO; using BinaryObjectScanner.Data; using BinaryObjectScanner.Interfaces; using SabreTools.IO.Extensions; -using SabreTools.Serialization.Interfaces; using SabreTools.Serialization.Wrappers; namespace BinaryObjectScanner.FileType @@ -12,7 +11,7 @@ namespace BinaryObjectScanner.FileType /// /// Executable or library /// - public class Executable : IDetectable + public class Executable : IDetectable, IExtractable { /// public string? Detect(string file, bool includeDebug) @@ -56,7 +55,7 @@ namespace BinaryObjectScanner.FileType var protections = new ProtectionDictionary(); // Try to create a wrapper for the proper executable type - IWrapper? wrapper; + SabreTools.Serialization.Interfaces.IWrapper? wrapper; try { wrapper = WrapperFactory.CreateExecutableWrapper(stream); @@ -82,11 +81,6 @@ namespace BinaryObjectScanner.FileType var subProtections = RunExecutableChecks(file, mz, StaticChecks.MSDOSExecutableCheckClasses, includeDebug); protections.Append(file, subProtections.Values); - - // Extractable checks - var extractedProtections - = HandleExtractableProtections(file, mz, subProtections.Keys, getProtections, includeDebug); - protections.Append(extractedProtections); } else if (wrapper is LinearExecutable lex) { @@ -94,11 +88,6 @@ namespace BinaryObjectScanner.FileType var subProtections = RunExecutableChecks(file, lex, StaticChecks.LinearExecutableCheckClasses, includeDebug); protections.Append(file, subProtections.Values); - - // Extractable checks - var extractedProtections - = HandleExtractableProtections(file, lex, subProtections.Keys, getProtections, includeDebug); - protections.Append(extractedProtections); } else if (wrapper is NewExecutable nex) { @@ -106,11 +95,6 @@ namespace BinaryObjectScanner.FileType var subProtections = RunExecutableChecks(file, nex, StaticChecks.NewExecutableCheckClasses, includeDebug); protections.Append(file, subProtections.Values); - - // Extractable checks - var extractedProtections - = HandleExtractableProtections(file, nex, subProtections.Keys, getProtections, includeDebug); - protections.Append(extractedProtections); } else if (wrapper is PortableExecutable pex) { @@ -118,16 +102,39 @@ namespace BinaryObjectScanner.FileType var subProtections = RunExecutableChecks(file, pex, StaticChecks.PortableExecutableCheckClasses, includeDebug); protections.Append(file, subProtections.Values); - - // Extractable checks - var extractedProtections - = HandleExtractableProtections(file, pex, subProtections.Keys, getProtections, includeDebug); - protections.Append(extractedProtections); } return protections; } + /// + public bool Extract(string file, string outDir, bool includeDebug) + { + if (!File.Exists(file)) + return false; + + using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + return Extract(fs, file, outDir, includeDebug); + } + + /// + public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) + { + // Create the wrapper + var exe = WrapperFactory.CreateExecutableWrapper(stream); + if (exe == null) + return false; + + // Extract all files + Directory.CreateDirectory(outDir); + if (exe is PortableExecutable pex) + pex.Extract(outDir, includeDebug); + else if (exe is NewExecutable nex) + nex.Extract(outDir, includeDebug); + + return true; + } + #region Check Runners /// @@ -211,104 +218,6 @@ namespace BinaryObjectScanner.FileType return protections; } - /// - /// Handle extractable protections, such as executable packers - /// - /// Name of the source file of the stream, for tracking - /// Executable to scan the contents of - /// Set of classes returned from Exectuable scans - /// Optional function for handling recursive protections - /// True to include debug data, false otherwise - /// Set of protections found from extraction, empty on error - private static ProtectionDictionary HandleExtractableProtections(string file, - T exe, - ICollection checks, - Func? getProtections, - bool includeDebug) - where T : WrapperBase - where U : IExecutableCheck - { - // Create the output dictionary - var protections = new ProtectionDictionary(); - - // If we have an invalid set of classes - if (checks == null) - return protections; - - // If we have any extractable packers - var extractables = new List>(); - foreach (var check in checks) - { - if (check is not IExtractableExecutable extractable) - continue; - - extractables.Add(extractable); - } - - extractables.IterateWithAction(extractable => - { - var subProtections = PerformExtractableCheck(extractable!, file, exe, getProtections, includeDebug); - protections.Append(subProtections); - }); - - return protections; - } - - /// - /// Handle files based on an IExtractableExecutable implementation - /// - /// Name of the source file of the stream, for tracking - /// Executable to scan the contents of - /// IExtractableExecutable class representing the file type - /// Optional function for handling recursive protections - /// True to include debug data, false otherwise - /// Set of protections in path, empty on error - private static ProtectionDictionary PerformExtractableCheck(IExtractableExecutable impl, - string file, - T exe, - Func? getProtections, - bool includeDebug) - where T : WrapperBase - { - // If we have an invalid extractable somehow - if (impl == null) - return []; - - // If the extractable file itself fails - try - { - // Extract and get the output path - string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - bool extracted = impl.Extract(file, exe, tempPath, includeDebug); - - // Collect and format all found protections - ProtectionDictionary? subProtections = null; - if (extracted && getProtections != null) - subProtections = getProtections(tempPath); - - // If temp directory cleanup fails - try - { - if (Directory.Exists(tempPath)) - Directory.Delete(tempPath, true); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } - - // Prepare the returned protections - subProtections?.StripFromKeys(tempPath); - subProtections?.PrependToKeys(file); - return subProtections ?? []; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return []; - } - } - #endregion } } diff --git a/BinaryObjectScanner/FileType/GCF.cs b/BinaryObjectScanner/FileType/GCF.cs index 6ea1ee9e..103d55ce 100644 --- a/BinaryObjectScanner/FileType/GCF.cs +++ b/BinaryObjectScanner/FileType/GCF.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - gcf.ExtractAll(outDir); + gcf.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/GZIP.cs b/BinaryObjectScanner/FileType/GZIP.cs deleted file mode 100644 index 8525a939..00000000 --- a/BinaryObjectScanner/FileType/GZIP.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.IO; -using BinaryObjectScanner.Interfaces; -using SabreTools.Compression.Deflate; - -namespace BinaryObjectScanner.FileType -{ - /// - /// gzip archive - /// - public class GZIP : IExtractable - { - /// - public bool Extract(string file, string outDir, bool includeDebug) - { - if (!File.Exists(file)) - return false; - - using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - return Extract(fs, file, outDir, includeDebug); - } - - /// - public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) - { - if (stream == null || !stream.CanRead) - return false; - - try - { - // Try opening the stream - using var gzipFile = new GZipStream(stream, CompressionMode.Decompress, true); - - // Ensure directory separators are consistent - string filename = Guid.NewGuid().ToString(); - if (Path.DirectorySeparatorChar == '\\') - filename = filename.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - filename = filename.Replace('\\', '/'); - - // Ensure the full output directory exists - filename = Path.Combine(outDir, filename); - var directoryName = Path.GetDirectoryName(filename); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - // Extract the file - using FileStream fs = File.OpenWrite(filename); - gzipFile.CopyTo(fs); - fs.Flush(); - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } - } - } -} diff --git a/BinaryObjectScanner/FileType/GZip.cs b/BinaryObjectScanner/FileType/GZip.cs new file mode 100644 index 00000000..febd2020 --- /dev/null +++ b/BinaryObjectScanner/FileType/GZip.cs @@ -0,0 +1,36 @@ +using System.IO; +using BinaryObjectScanner.Interfaces; + +namespace BinaryObjectScanner.FileType +{ + /// + /// gzip archive + /// + public class GZip : IExtractable + { + /// + public bool Extract(string file, string outDir, bool includeDebug) + { + if (!File.Exists(file)) + return false; + + using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + return Extract(fs, file, outDir, includeDebug); + } + + /// + public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) + { + // Create the wrapper + var gcf = SabreTools.Serialization.Wrappers.GZip.Create(stream); + if (gcf == null) + return false; + + // Loop through and extract all files + Directory.CreateDirectory(outDir); + gcf.Extract(outDir, includeDebug); + + return true; + } + } +} diff --git a/BinaryObjectScanner/FileType/InstallShieldArchiveV3.cs b/BinaryObjectScanner/FileType/InstallShieldArchiveV3.cs index 4ac3cd5c..126090b4 100644 --- a/BinaryObjectScanner/FileType/InstallShieldArchiveV3.cs +++ b/BinaryObjectScanner/FileType/InstallShieldArchiveV3.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - isv3.ExtractAll(outDir); + isv3.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/InstallShieldCAB.cs b/BinaryObjectScanner/FileType/InstallShieldCAB.cs index aafad74f..419fde18 100644 --- a/BinaryObjectScanner/FileType/InstallShieldCAB.cs +++ b/BinaryObjectScanner/FileType/InstallShieldCAB.cs @@ -1,8 +1,5 @@ -using System; -using System.IO; -using System.Text.RegularExpressions; +using System.IO; using BinaryObjectScanner.Interfaces; -using UnshieldSharp; namespace BinaryObjectScanner.FileType { @@ -24,81 +21,16 @@ namespace BinaryObjectScanner.FileType /// public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) { - // Handles getting full path if relative paths were passed. - file = Path.GetFullPath(file); - // Get the name of the first cabinet file or header - var directory = Path.GetDirectoryName(file); - string noExtension = Path.GetFileNameWithoutExtension(file); - - bool shouldScanCabinet; - if (directory == null) - { - string filenamePattern = noExtension; - filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty); - bool cabinetHeaderExists = File.Exists(filenamePattern + "1.hdr"); - shouldScanCabinet = cabinetHeaderExists - ? file.Equals(filenamePattern + "1.hdr", StringComparison.OrdinalIgnoreCase) - : file.Equals(filenamePattern + "1.cab", StringComparison.OrdinalIgnoreCase); - } - else - { - string filenamePattern = Path.Combine(directory, noExtension); - filenamePattern = new Regex(@"\d+$").Replace(filenamePattern, string.Empty); - bool cabinetHeaderExists = File.Exists(Path.Combine(directory, filenamePattern + "1.hdr")); - shouldScanCabinet = cabinetHeaderExists - ? file.Equals(Path.Combine(directory, filenamePattern + "1.hdr"), StringComparison.OrdinalIgnoreCase) - : file.Equals(Path.Combine(directory, filenamePattern + "1.cab"), StringComparison.OrdinalIgnoreCase); - } - - // If we have anything but the first file - if (!shouldScanCabinet) + // Create the wrapper + var iscab = SabreTools.Serialization.Wrappers.InstallShieldCabinet.Create(stream); + if (iscab == null) return false; - try - { - if (!File.Exists(file)) - return false; + // Loop through and extract all files + Directory.CreateDirectory(outDir); + iscab.Extract(outDir, includeDebug); - var cabfile = InstallShieldCabinet.Open(file); - if (cabfile?.HeaderList == null) - return false; - - for (int i = 0; i < cabfile.HeaderList.FileCount; i++) - { - try - { - // Check if the file is valid first - if (!cabfile.HeaderList.FileIsValid(i)) - continue; - - // Ensure directory separators are consistent - string filename = cabfile.HeaderList.GetFileName(i) ?? $"BAD_FILENAME{i}"; - if (Path.DirectorySeparatorChar == '\\') - filename = filename.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - filename = filename.Replace('\\', '/'); - - // Ensure the full output directory exists - filename = Path.Combine(outDir, filename); - var directoryName = Path.GetDirectoryName(filename); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - cabfile.FileSave(i, filename); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } - } - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } + return true; } } } diff --git a/BinaryObjectScanner/FileType/LZKWAJ.cs b/BinaryObjectScanner/FileType/LZKWAJ.cs index 76ed91c0..4bf837fb 100644 --- a/BinaryObjectScanner/FileType/LZKWAJ.cs +++ b/BinaryObjectScanner/FileType/LZKWAJ.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - kwaj.Extract(outDir); + kwaj.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/LZQBasic.cs b/BinaryObjectScanner/FileType/LZQBasic.cs index bace4f26..59be9c32 100644 --- a/BinaryObjectScanner/FileType/LZQBasic.cs +++ b/BinaryObjectScanner/FileType/LZQBasic.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - qbasic.Extract(outDir); + qbasic.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/LZSZDD.cs b/BinaryObjectScanner/FileType/LZSZDD.cs index 216de535..882a8fa5 100644 --- a/BinaryObjectScanner/FileType/LZSZDD.cs +++ b/BinaryObjectScanner/FileType/LZSZDD.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - szdd.Extract(Path.GetFileName(file), outDir); + szdd.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/MPQ.cs b/BinaryObjectScanner/FileType/MPQ.cs index cc3a26da..08b43304 100644 --- a/BinaryObjectScanner/FileType/MPQ.cs +++ b/BinaryObjectScanner/FileType/MPQ.cs @@ -1,8 +1,5 @@ using System.IO; using BinaryObjectScanner.Interfaces; -#if (NET452_OR_GREATER || NETCOREAPP) && (WINX86 || WINX64) -using StormLibSharp; -#endif namespace BinaryObjectScanner.FileType { @@ -21,73 +18,19 @@ namespace BinaryObjectScanner.FileType return Extract(fs, file, outDir, includeDebug); } - // TODO: Add stream opening support /// public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) { -#if NET20 || NET35 || !(WINX86 || WINX64) - // Not supported for old .NET due to feature requirements - // Not supported in non-Windows builds due to DLL requirements - return false; -#else - try - { - if (!File.Exists(file)) - return false; - - // Try to open the archive and listfile - var mpqArchive = new MpqArchive(file, FileAccess.Read); - string? listfile = null; - MpqFileStream listStream = mpqArchive.OpenFile("(listfile)"); - - // If we can't read the listfile, we just return - if (!listStream.CanRead) - return false; - - // Read the listfile in for processing - using (var sr = new StreamReader(listStream)) - { - listfile = sr.ReadToEnd(); - } - - // Split the listfile by newlines - string[] listfileLines = listfile.Replace("\r\n", "\n").Split('\n'); - - // Loop over each entry - foreach (string sub in listfileLines) - { - // Ensure directory separators are consistent - string filename = sub; - if (Path.DirectorySeparatorChar == '\\') - filename = filename.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - filename = filename.Replace('\\', '/'); - - // Ensure the full output directory exists - filename = Path.Combine(outDir, filename); - var directoryName = Path.GetDirectoryName(filename); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - // Try to write the data - try - { - mpqArchive.ExtractFile(sub, filename); - } - catch (System.Exception ex) - { - if (includeDebug) System.Console.WriteLine(ex); - } - } - - return true; - } - catch (System.Exception ex) - { - if (includeDebug) System.Console.WriteLine(ex); + // Create the wrapper + var mpq = SabreTools.Serialization.Wrappers.MoPaQ.Create(stream); + if (mpq == null) return false; - } -#endif + + // Loop through and extract all files + Directory.CreateDirectory(outDir); + mpq.Extract(outDir, includeDebug); + + return true; } } } diff --git a/BinaryObjectScanner/FileType/MicrosoftCAB.cs b/BinaryObjectScanner/FileType/MicrosoftCAB.cs index 12fe785e..59babbf7 100644 --- a/BinaryObjectScanner/FileType/MicrosoftCAB.cs +++ b/BinaryObjectScanner/FileType/MicrosoftCAB.cs @@ -1,16 +1,11 @@ -using System; -using System.IO; +using System.IO; using BinaryObjectScanner.Interfaces; -using SabreTools.IO.Extensions; -using SabreTools.Models.MicrosoftCabinet; namespace BinaryObjectScanner.FileType { /// /// Microsoft cabinet file /// - /// Specification available at - /// public class MicrosoftCAB : IExtractable { /// @@ -26,457 +21,16 @@ namespace BinaryObjectScanner.FileType /// public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) { - // TODO: Remove once Serialization is updated - - // Get a wrapper for the set, if possible - SabreTools.Serialization.Wrappers.MicrosoftCabinet? current; - if (File.Exists(file)) - current = OpenSet(file); - else - current = SabreTools.Serialization.Wrappers.MicrosoftCabinet.Create(stream); - - // Validate the header exists - if (current?.Model?.Header == null) + // Create the wrapper + var mscab = SabreTools.Serialization.Wrappers.MicrosoftCabinet.Create(stream); + if (mscab == null) return false; - try - { - // Loop through the cabinets - do - { - ExtractCabinet(current, file, outDir, forwardOnly: true, includeDebug); - current = OpenNext(current, file); - } - while (current?.Model?.Header != null); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } + // Loop through and extract all files + Directory.CreateDirectory(outDir); + mscab.Extract(outDir, includeDebug); return true; } - - /// - /// Open a cabinet set for reading, if possible - /// - /// Filename for one cabinet in the set - /// Wrapper representing the set, null on error - /// TODO: Remove once Serialization is updated - private static SabreTools.Serialization.Wrappers.MicrosoftCabinet? OpenSet(string? filename) - { - // If the file is invalid - if (string.IsNullOrEmpty(filename)) - return null; - else if (!File.Exists(filename!)) - return null; - - // Get the full file path and directory - filename = Path.GetFullPath(filename); - - // Read in the current file and try to parse - var stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - var current = SabreTools.Serialization.Wrappers.MicrosoftCabinet.Create(stream); - if (current?.Model?.Header == null) - return null; - - // Seek to the first part of the cabinet set - while (current.Model.Header?.CabinetPrev != null) - { - // Attempt to open the previous cabinet - var prev = OpenPrevious(current, filename); - if (prev?.Model?.Header == null) - break; - - // Assign previous as new current - current = prev; - } - - // Return the start of the set - return current; - } - - /// - /// Extract a cabinet file to an output directory, if possible - /// - /// Filename for one cabinet in the set, if available - /// Path to the output directory - /// True to include debug data, false otherwise - /// Indicates if all files were able to be extracted - /// TODO: Remove once Serialization is updated - private static bool ExtractCabinet(SabreTools.Serialization.Wrappers.MicrosoftCabinet cabArchive, string? filename, string outDir, bool forwardOnly, bool includeDebug) - { - // If the archive is invalid - if (cabArchive?.Model?.Folders == null || cabArchive.Model.Folders.Length == 0) - return false; - - try - { - // Loop through the folders - for (int f = 0; f < cabArchive.Model.Folders.Length; f++) - { - var folder = cabArchive.Model.Folders[f]; - ExtractFolder(cabArchive, filename, outDir, folder, f, includeDebug); - } - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } - } - - /// - /// Extract the contents of a single folder - /// - /// Filename for one cabinet in the set, if available - /// Path to the output directory - /// Folder containing the blocks to decompress - /// Index of the folder in the cabinet - /// True to include debug data, false otherwise - /// TODO: Remove once Serialization is updated - private static void ExtractFolder(SabreTools.Serialization.Wrappers.MicrosoftCabinet cabArchive, - string? filename, - string outDir, - CFFOLDER? folder, - int folderIndex, - bool includeDebug) - { - // Decompress the blocks, if possible - using var blockStream = DecompressBlocks(cabArchive, filename, folder, folderIndex, includeDebug); - if (blockStream == null || blockStream.Length == 0) - return; - - // Loop through the files - var files = GetFiles(cabArchive, folderIndex); - for (int i = 0; i < files.Length; i++) - { - var file = files[i]; - ExtractFile(outDir, blockStream, file, includeDebug); - } - } - - /// - /// Extract the contents of a single file - /// - /// Path to the output directory - /// Stream representing the uncompressed block data - /// File information - /// True to include debug data, false otherwise - /// TODO: Remove once Serialization is updated - private static void ExtractFile(string outDir, Stream blockStream, CFFILE file, bool includeDebug) - { - try - { - blockStream.Seek(file.FolderStartOffset, SeekOrigin.Begin); - byte[] fileData = blockStream.ReadBytes((int)file.FileSize); - - // Ensure directory separators are consistent - string fileName = file.Name!; - if (Path.DirectorySeparatorChar == '\\') - fileName = fileName.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - fileName = fileName.Replace('\\', '/'); - - string tempFile = Path.Combine(outDir, fileName); - var directoryName = Path.GetDirectoryName(tempFile); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - using var of = File.OpenWrite(tempFile); - of.Write(fileData, 0, fileData.Length); - of.Flush(); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } - } - - /// - /// Decompress all blocks for a folder - /// - /// Filename for one cabinet in the set, if available - /// Folder containing the blocks to decompress - /// Index of the folder in the cabinet - /// True to include debug data, false otherwise - /// Stream representing the decompressed data on success, null otherwise - /// TODO: Remove once Serialization is updated - private static Stream? DecompressBlocks(SabreTools.Serialization.Wrappers.MicrosoftCabinet cabArchive, string? filename, CFFOLDER? folder, int folderIndex, bool includeDebug) - { - // Ensure data blocks - var dataBlocks = GetDataBlocks(cabArchive, filename, folder, folderIndex); - if (dataBlocks == null || dataBlocks.Length == 0) - return null; - - // Get the compression type - var compressionType = GetCompressionType(folder!); - - // Setup decompressors - var mszip = SabreTools.Compression.MSZIP.Decompressor.Create(); - //uint quantumWindowBits = (uint)(((ushort)folder.CompressionType >> 8) & 0x1f); - - // Loop through the data blocks - var ms = new MemoryStream(); - for (int i = 0; i < dataBlocks.Length; i++) - { - var db = dataBlocks[i]; - if (db.CompressedData == null) - continue; - - // Get the data to be processed - byte[] blockData = db.CompressedData; - - // If the block is continued, append - bool continuedBlock = false; - if (db.UncompressedSize == 0) - { - var nextBlock = dataBlocks[i + 1]; - byte[]? nextData = nextBlock.CompressedData; - if (nextData == null) - continue; - - continuedBlock = true; - blockData = [.. blockData, .. nextData]; - db.CompressedSize += nextBlock.CompressedSize; - db.UncompressedSize = nextBlock.UncompressedSize; - } - - // Get the uncompressed data block - byte[] data = compressionType switch - { - CompressionType.TYPE_NONE => blockData, - CompressionType.TYPE_MSZIP => DecompressMSZIPBlock(folderIndex, mszip, i, db, blockData, includeDebug), - - // TODO: Unsupported - CompressionType.TYPE_QUANTUM => [], - CompressionType.TYPE_LZX => [], - - // Should be impossible - _ => [], - }; - - // Write the uncompressed data block - ms.Write(data, 0, data.Length); - ms.Flush(); - - // Increment additionally if we had a continued block - if (continuedBlock) i++; - } - - return ms; - } - - /// - /// Decompress an MS-ZIP block using an existing decompressor - /// - /// Index of the folder in the cabinet - /// MS-ZIP decompressor with persistent state - /// Index of the block within the folder - /// Block data to be used for decompression - /// Block data to be used for decompression - /// True to include debug data, false otherwise - /// Byte array representing the decompressed data, empty on error - /// TODO: Remove once Serialization is updated - private static byte[] DecompressMSZIPBlock(int folderIndex, SabreTools.Compression.MSZIP.Decompressor mszip, int blockIndex, CFDATA block, byte[] blockData, bool includeDebug) - { - try - { - // Decompress to a temporary stream - using var stream = new MemoryStream(); - mszip.CopyTo(blockData, stream); - - // Pad to the correct size but throw a warning about this - if (stream.Length < block.UncompressedSize) - { - if (includeDebug) - Console.Error.WriteLine($"Data block {blockIndex} in folder {folderIndex} had mismatching sizes. Expected: {block.UncompressedSize}, Got: {stream.Length}"); - - byte[] padding = new byte[block.UncompressedSize - stream.Length]; - stream.Write(padding, 0, padding.Length); - } - - // Return the byte array data - return stream.ToArray(); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return []; - } - } - - /// - /// Get the unmasked compression type for a folder - /// - /// Folder to get the compression type for - /// Compression type on success, on error - /// TODO: Remove once Serialization is updated - private static CompressionType GetCompressionType(CFFOLDER folder) - { - if ((folder!.CompressionType & CompressionType.MASK_TYPE) == CompressionType.TYPE_NONE) - return CompressionType.TYPE_NONE; - else if ((folder.CompressionType & CompressionType.MASK_TYPE) == CompressionType.TYPE_MSZIP) - return CompressionType.TYPE_MSZIP; - else if ((folder.CompressionType & CompressionType.MASK_TYPE) == CompressionType.TYPE_QUANTUM) - return CompressionType.TYPE_QUANTUM; - else if ((folder.CompressionType & CompressionType.MASK_TYPE) == CompressionType.TYPE_LZX) - return CompressionType.TYPE_LZX; - else - return (CompressionType)ushort.MaxValue; - } - - /// - /// Get the set of data blocks for a folder - /// - /// Filename for one cabinet in the set, if available - /// Folder containing the blocks to decompress - /// Index of the folder in the cabinet - /// Indicates if previous cabinets should be ignored - /// Indicates if next cabinets should be ignored - /// Array of data blocks on success, null otherwise - /// TODO: Remove once Serialization is updated - private static CFDATA[]? GetDataBlocks(SabreTools.Serialization.Wrappers.MicrosoftCabinet cabArchive, string? filename, CFFOLDER? folder, int folderIndex, bool skipPrev = false, bool skipNext = false) - { - // Skip invalid folders - if (folder?.DataBlocks == null || folder.DataBlocks.Length == 0) - return null; - - // Get all files for the folder - var files = GetFiles(cabArchive, folderIndex); - if (files.Length == 0) - return folder.DataBlocks; - - // Check if the folder spans in either direction - bool spanPrev = Array.Exists(files, f => f.FolderIndex == FolderIndex.CONTINUED_FROM_PREV || f.FolderIndex == FolderIndex.CONTINUED_PREV_AND_NEXT); - bool spanNext = Array.Exists(files, f => f.FolderIndex == FolderIndex.CONTINUED_TO_NEXT || f.FolderIndex == FolderIndex.CONTINUED_PREV_AND_NEXT); - - // If the folder spans backward and Prev is not being skipped - CFDATA[] prevBlocks = []; - if (!skipPrev && spanPrev) - { - // Get all blocks from Prev - var prev = OpenPrevious(cabArchive, filename); - if (prev?.Model?.Header != null && prev.Model.Folders != null) - { - int prevFolderIndex = prev.Model.Header.FolderCount; - var prevFolder = prev.Model.Folders[prevFolderIndex - 1]; - prevBlocks = GetDataBlocks(prev, filename, prevFolder, prevFolderIndex, skipNext: true) ?? []; - } - } - - // If the folder spans forward and Next is not being skipped - CFDATA[] nextBlocks = []; - if (!skipNext && spanNext) - { - // Get all blocks from Prev - var next = OpenNext(cabArchive, filename); - if (next?.Model?.Header != null && next.Model.Folders != null) - { - var nextFolder = next.Model.Folders[0]; - nextBlocks = GetDataBlocks(next, filename, nextFolder, 0, skipPrev: true) ?? []; - } - } - - // Return all found blocks in order - return [.. prevBlocks, .. folder.DataBlocks, .. nextBlocks]; - } - - /// - /// Get all files for the current folder index - /// - /// TODO: Remove once Serialization is updated - private static CFFILE[] GetFiles(SabreTools.Serialization.Wrappers.MicrosoftCabinet cabArchive, int folderIndex) - { - // Ignore invalid archives - if (cabArchive.Model.Files == null) - return []; - - // Get all files with a name and matching index - return Array.FindAll(cabArchive.Model.Files, f => - { - if (string.IsNullOrEmpty(f.Name)) - return false; - - int fileFolder = GetFolderIndex(cabArchive, f); - return fileFolder == folderIndex; - }); - } - - /// - /// Get the corrected folder index - /// - /// TODO: Remove once Serialization is updated - private static int GetFolderIndex(SabreTools.Serialization.Wrappers.MicrosoftCabinet cabArchive, CFFILE file) - { - return file.FolderIndex switch - { - FolderIndex.CONTINUED_FROM_PREV => 0, - FolderIndex.CONTINUED_TO_NEXT => (cabArchive.Model.Header?.FolderCount ?? 1) - 1, - FolderIndex.CONTINUED_PREV_AND_NEXT => 0, - _ => (int)file.FolderIndex, - }; - } - - /// - /// Open the next archive, if possible - /// - /// Filename for one cabinet in the set - /// TODO: Remove once Serialization is updated - private static SabreTools.Serialization.Wrappers.MicrosoftCabinet? OpenNext(SabreTools.Serialization.Wrappers.MicrosoftCabinet cabArchive, string? filename) - { - // Ignore invalid archives - if (cabArchive.Model?.Header == null || string.IsNullOrEmpty(filename)) - return null; - - // Normalize the filename - filename = Path.GetFullPath(filename); - - // Get if the cabinet has a next part - string? next = cabArchive.Model.Header.CabinetNext; - if (string.IsNullOrEmpty(next)) - return null; - - // Get the full next path - string? folder = Path.GetDirectoryName(filename); - if (folder != null) - next = Path.Combine(folder, next); - - // Open and return the next cabinet - var fs = File.Open(next, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - return SabreTools.Serialization.Wrappers.MicrosoftCabinet.Create(fs); - } - - /// - /// Open the previous archive, if possible - /// - /// Filename for one cabinet in the set - /// TODO: Remove once Serialization is updated - private static SabreTools.Serialization.Wrappers.MicrosoftCabinet? OpenPrevious(SabreTools.Serialization.Wrappers.MicrosoftCabinet cabArchive, string? filename) - { - // Ignore invalid archives - if (cabArchive.Model?.Header == null || string.IsNullOrEmpty(filename)) - return null; - - // Normalize the filename - filename = Path.GetFullPath(filename); - - // Get if the cabinet has a previous part - string? prev = cabArchive.Model.Header.CabinetPrev; - if (string.IsNullOrEmpty(prev)) - return null; - - // Get the full next path - string? folder = Path.GetDirectoryName(filename); - if (folder != null) - prev = Path.Combine(folder, prev); - - // Open and return the previous cabinet - var fs = File.Open(prev, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - return SabreTools.Serialization.Wrappers.MicrosoftCabinet.Create(fs); - } } } diff --git a/BinaryObjectScanner/FileType/PAK.cs b/BinaryObjectScanner/FileType/PAK.cs index 2614a52d..814320cb 100644 --- a/BinaryObjectScanner/FileType/PAK.cs +++ b/BinaryObjectScanner/FileType/PAK.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - pak.ExtractAll(outDir); + pak.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/PFF.cs b/BinaryObjectScanner/FileType/PFF.cs index 2ef57a61..759efb54 100644 --- a/BinaryObjectScanner/FileType/PFF.cs +++ b/BinaryObjectScanner/FileType/PFF.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Extract all files Directory.CreateDirectory(outDir); - pff.ExtractAll(outDir); + pff.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/PKZIP.cs b/BinaryObjectScanner/FileType/PKZIP.cs index 46046199..fd7f2b9c 100644 --- a/BinaryObjectScanner/FileType/PKZIP.cs +++ b/BinaryObjectScanner/FileType/PKZIP.cs @@ -1,11 +1,5 @@ -using System; -using System.IO; +using System.IO; using BinaryObjectScanner.Interfaces; -#if NET462_OR_GREATER || NETCOREAPP -using SharpCompress.Archives; -using SharpCompress.Archives.Zip; -using SharpCompress.Readers; -#endif namespace BinaryObjectScanner.FileType { @@ -16,96 +10,27 @@ namespace BinaryObjectScanner.FileType { /// public bool Extract(string file, string outDir, bool includeDebug) - => Extract(file, outDir, lookForHeader: false, includeDebug); - - /// - public bool Extract(string file, string outDir, bool lookForHeader, bool includeDebug) { if (!File.Exists(file)) return false; using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - return Extract(fs, file, outDir, lookForHeader, includeDebug); + return Extract(fs, file, outDir, includeDebug); } /// public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) - => Extract(stream, file, outDir, lookForHeader: false, includeDebug); - - /// - public bool Extract(Stream? stream, string file, string outDir, bool lookForHeader, bool includeDebug) { - if (stream == null || !stream.CanRead) + // Create the wrapper + var pkzip = SabreTools.Serialization.Wrappers.PKZIP.Create(stream); + if (pkzip == null) return false; -#if NET462_OR_GREATER || NETCOREAPP - try - { - var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader }; - var zipFile = ZipArchive.Open(stream, readerOptions); + // Loop through and extract all files + Directory.CreateDirectory(outDir); + pkzip.Extract(outDir, includeDebug); - // If the file exists - if (!string.IsNullOrEmpty(file) && File.Exists(file!)) - { - // Find all file parts - FileInfo[] parts = [.. ArchiveFactory.GetFileParts(new FileInfo(file))]; - - // If there are multiple parts - if (parts.Length > 1) - zipFile = ZipArchive.Open(parts, readerOptions); - - // Try to read the file path if no entries are found - else if (zipFile.Entries.Count == 0) - zipFile = ZipArchive.Open(parts, readerOptions); - } - - foreach (var entry in zipFile.Entries) - { - try - { - // If the entry is a directory - if (entry.IsDirectory) - continue; - - // If the entry has an invalid key - if (entry.Key == null) - continue; - - // If the entry is partial due to an incomplete multi-part archive, skip it - if (!entry.IsComplete) - continue; - - // Ensure directory separators are consistent - string filename = entry.Key; - if (Path.DirectorySeparatorChar == '\\') - filename = filename.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - filename = filename.Replace('\\', '/'); - - // Ensure the full output directory exists - filename = Path.Combine(outDir, filename); - var directoryName = Path.GetDirectoryName(filename); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - entry.WriteToFile(filename); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } - } - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } -#else - return false; -#endif + return true; } } } diff --git a/BinaryObjectScanner/FileType/Quantum.cs b/BinaryObjectScanner/FileType/Quantum.cs index 4033d157..0b898ffd 100644 --- a/BinaryObjectScanner/FileType/Quantum.cs +++ b/BinaryObjectScanner/FileType/Quantum.cs @@ -22,121 +22,13 @@ namespace BinaryObjectScanner.FileType public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) { // Create the wrapper - var quantum = SabreTools.Serialization.Wrappers.Quantum.Create(stream); - if (quantum == null) + var qtm = SabreTools.Serialization.Wrappers.Quantum.Create(stream); + if (qtm == null) return false; - // Extract all files + // Loop through and extract all files Directory.CreateDirectory(outDir); - ExtractAll(quantum, outDir); - - return true; - } - - /// - /// Extract all files from the Quantum archive to an output directory - /// - /// Output directory to write to - /// True if all files extracted, false otherwise - public static bool ExtractAll(SabreTools.Serialization.Wrappers.Quantum item, string outputDirectory) - { - // If we have no files - if (item.Model.FileList == null || item.Model.FileList.Length == 0) - return false; - - // Loop through and extract all files to the output - bool allExtracted = true; - for (int i = 0; i < item.Model.FileList.Length; i++) - { - allExtracted &= ExtractFile(item, i, outputDirectory); - } - - return allExtracted; - } - - /// - /// Extract a file from the Quantum archive to an output directory by index - /// - /// File index to extract - /// Output directory to write to - /// True if the file extracted, false otherwise - public static bool ExtractFile(SabreTools.Serialization.Wrappers.Quantum item, int index, string outputDirectory) - { - // If we have no files - if (item.Model.Header == null || item.Model.Header.FileCount == 0 || item.Model.FileList == null || item.Model.FileList.Length == 0) - return false; - - // If we have an invalid index - if (index < 0 || index >= item.Model.FileList.Length) - return false; - - // Get the file information - var fileDescriptor = item.Model.FileList[index]; - - // Read the entire compressed data - int compressedDataOffset = (int)item.Model.CompressedDataOffset; - int compressedDataLength = item.GetEndOfFile() - compressedDataOffset; - var compressedData = item.ReadFromDataSource(compressedDataOffset, compressedDataLength); - - // TODO: Figure out decompression - // - Single-file archives seem to work - // - Single-file archives with files that span a window boundary seem to work - // - The first files in each archive seem to work - return false; - - // // Setup the decompression state - // State state = new State(); - // Decompressor.InitState(state, TableSize, CompressionFlags); - - // // Decompress the entire array - // int decompressedDataLength = (int)FileList.Sum(fd => fd.ExpandedFileSize); - // byte[] decompressedData = new byte[decompressedDataLength]; - // Decompressor.Decompress(state, compressedData.Length, compressedData, decompressedData.Length, decompressedData); - - // // Read the data - // int offset = (int)FileList.Take(index).Sum(fd => fd.ExpandedFileSize); - // byte[] data = new byte[fileDescriptor.ExpandedFileSize]; - // Array.Copy(decompressedData, offset, data, 0, data.Length); - - // // Loop through all files before the current - // for (int i = 0; i < index; i++) - // { - // // Decompress the next block of data - // byte[] tempData = new byte[FileList[i].ExpandedFileSize]; - // int lastRead = Decompressor.Decompress(state, compressedData.Length, compressedData, tempData.Length, tempData); - // compressedData = new ReadOnlySpan(compressedData, (lastRead), compressedData.Length - (lastRead)).ToArray(); - // } - - // // Read the data - // byte[] data = new byte[fileDescriptor.ExpandedFileSize]; - // _ = Decompressor.Decompress(state, compressedData.Length, compressedData, data.Length, data); - - // // Create the filename - // string filename = fileDescriptor.FileName; - - // // If we have an invalid output directory - // if (string.IsNullOrEmpty(outputDirectory)) - // return false; - - // // Create the full output path - // filename = Path.Combine(outputDirectory, filename); - - // // Ensure the output directory is created - // Directory.CreateDirectory(Path.GetDirectoryName(filename)); - - // // Try to write the data - // try - // { - // // Open the output file for writing - // using (Stream fs = File.OpenWrite(filename)) - // { - // fs.Write(data, 0, data.Length); - // } - // } - // catch - // { - // return false; - // } + qtm.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/RAR.cs b/BinaryObjectScanner/FileType/RAR.cs index 30228a6c..6a297fbf 100644 --- a/BinaryObjectScanner/FileType/RAR.cs +++ b/BinaryObjectScanner/FileType/RAR.cs @@ -1,12 +1,5 @@ -using System; -using System.IO; +using System.IO; using BinaryObjectScanner.Interfaces; -#if NET462_OR_GREATER || NETCOREAPP -using SharpCompress.Archives; -using SharpCompress.Archives.Rar; -using SharpCompress.Common; -using SharpCompress.Readers; -#endif namespace BinaryObjectScanner.FileType { @@ -17,137 +10,27 @@ namespace BinaryObjectScanner.FileType { /// public bool Extract(string file, string outDir, bool includeDebug) - => Extract(file, outDir, lookForHeader: false, includeDebug); - - /// - public bool Extract(string file, string outDir, bool lookForHeader, bool includeDebug) { if (!File.Exists(file)) return false; using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - return Extract(fs, file, outDir, lookForHeader, includeDebug); + return Extract(fs, file, outDir, includeDebug); } /// public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) - => Extract(stream, file, outDir, lookForHeader: false, includeDebug); - - /// - public bool Extract(Stream? stream, string file, string outDir, bool lookForHeader, bool includeDebug) { - if (stream == null || !stream.CanRead) + // Create the wrapper + var rar = SabreTools.Serialization.Wrappers.RAR.Create(stream); + if (rar == null) return false; -#if NET462_OR_GREATER || NETCOREAPP - try - { - var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader }; - RarArchive rarFile = RarArchive.Open(stream, readerOptions); - - // If the file exists - if (!string.IsNullOrEmpty(file) && File.Exists(file!)) - { - // Find all file parts - FileInfo[] parts = [.. ArchiveFactory.GetFileParts(new FileInfo(file))]; - - // If there are multiple parts - if (parts.Length > 1) - rarFile = RarArchive.Open(parts, readerOptions); - - // Try to read the file path if no entries are found - else if (rarFile.Entries.Count == 0) - rarFile = RarArchive.Open(parts, readerOptions); - } - - if (rarFile.IsSolid) - return ExtractSolid(rarFile, outDir, includeDebug); - else - return ExtractNonSolid(rarFile, outDir, includeDebug); - - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } -#else - return false; -#endif - } - -#if NET462_OR_GREATER || NETCOREAPP - - /// - /// Extraction method for non-solid archives. This iterates over each entry in the archive to extract every - /// file individually, in order to extract all valid files from the archive. - /// - private static bool ExtractNonSolid(RarArchive rarFile, string outDir, bool includeDebug) - { - foreach (var entry in rarFile.Entries) - { - try - { - // If the entry is a directory - if (entry.IsDirectory) - continue; - - // If the entry has an invalid key - if (entry.Key == null) - continue; - - // If we have a partial entry due to an incomplete multi-part archive, skip it - if (!entry.IsComplete) - continue; - - // Ensure directory separators are consistent - string filename = entry.Key; - if (Path.DirectorySeparatorChar == '\\') - filename = filename.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - filename = filename.Replace('\\', '/'); - - // Ensure the full output directory exists - filename = Path.Combine(outDir, filename); - var directoryName = Path.GetDirectoryName(filename); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - entry.WriteToFile(filename); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } - } - return true; - } - - /// - /// Extraction method for solid archives. Uses ExtractAllEntries because extraction for solid archives must be - /// done sequentially, and files beyond a corrupted point in a solid archive will be unreadable anyways. - /// - private static bool ExtractSolid(RarArchive rarFile, string outDir, bool includeDebug) - { - try - { - if (!Directory.Exists(outDir)) - Directory.CreateDirectory(outDir); - - rarFile.WriteToDirectory(outDir, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true, - }); - - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } + // Loop through and extract all files + Directory.CreateDirectory(outDir); + rar.Extract(outDir, includeDebug); return true; } -#endif } } \ No newline at end of file diff --git a/BinaryObjectScanner/FileType/SGA.cs b/BinaryObjectScanner/FileType/SGA.cs index bba112ce..1ceca005 100644 --- a/BinaryObjectScanner/FileType/SGA.cs +++ b/BinaryObjectScanner/FileType/SGA.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - sga.ExtractAll(outDir); + sga.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/SevenZip.cs b/BinaryObjectScanner/FileType/SevenZip.cs index fd25fb3a..52694741 100644 --- a/BinaryObjectScanner/FileType/SevenZip.cs +++ b/BinaryObjectScanner/FileType/SevenZip.cs @@ -1,12 +1,5 @@ -using System; -using System.IO; +using System.IO; using BinaryObjectScanner.Interfaces; -#if NET462_OR_GREATER || NETCOREAPP -using SharpCompress.Archives; -using SharpCompress.Archives.SevenZip; -using SharpCompress.Common; -using SharpCompress.Readers; -#endif namespace BinaryObjectScanner.FileType { @@ -17,138 +10,27 @@ namespace BinaryObjectScanner.FileType { /// public bool Extract(string file, string outDir, bool includeDebug) - => Extract(file, outDir, lookForHeader: false, includeDebug); - - /// - public bool Extract(string file, string outDir, bool lookForHeader, bool includeDebug) { if (!File.Exists(file)) return false; using var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - return Extract(fs, file, outDir, lookForHeader, includeDebug); + return Extract(fs, file, outDir, includeDebug); } /// public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) - => Extract(stream, file, outDir, lookForHeader: false, includeDebug); - - /// - public bool Extract(Stream? stream, string file, string outDir, bool lookForHeader, bool includeDebug) { - if (stream == null || !stream.CanRead) + // Create the wrapper + var sevenZip = SabreTools.Serialization.Wrappers.SevenZip.Create(stream); + if (sevenZip == null) return false; -#if NET462_OR_GREATER || NETCOREAPP - try - { - var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader }; - var sevenZip = SevenZipArchive.Open(stream, readerOptions); - - // If the file exists - if (!string.IsNullOrEmpty(file) && File.Exists(file!)) - { - // Find all file parts - FileInfo[] parts = [.. ArchiveFactory.GetFileParts(new FileInfo(file))]; - - // If there are multiple parts - if (parts.Length > 1) - sevenZip = SevenZipArchive.Open(parts, readerOptions); - - // Try to read the file path if no entries are found - else if (sevenZip.Entries.Count == 0) - sevenZip = SevenZipArchive.Open(parts, readerOptions); - } - - // Currently doesn't flag solid 7z archives with only 1 solid block as solid, but practically speaking - // this is not much of a concern. - if (sevenZip.IsSolid) - return ExtractSolid(sevenZip, outDir, includeDebug); - else - return ExtractNonSolid(sevenZip, outDir, includeDebug); - - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } -#else - return false; -#endif - } - -#if NET462_OR_GREATER || NETCOREAPP - /// - /// Extraction method for non-solid archives. This iterates over each entry in the archive to extract every - /// file individually, in order to extract all valid files from the archive. - /// - private static bool ExtractNonSolid(SevenZipArchive sevenZip, string outDir, bool includeDebug) - { - foreach (var entry in sevenZip.Entries) - { - try - { - // If the entry is a directory - if (entry.IsDirectory) - continue; - - // If the entry has an invalid key - if (entry.Key == null) - continue; - - // If we have a partial entry due to an incomplete multi-part archive, skip it - if (!entry.IsComplete) - continue; - - // Ensure directory separators are consistent - string filename = entry.Key; - if (Path.DirectorySeparatorChar == '\\') - filename = filename.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - filename = filename.Replace('\\', '/'); - - // Ensure the full output directory exists - filename = Path.Combine(outDir, filename); - var directoryName = Path.GetDirectoryName(filename); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - entry.WriteToFile(filename); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } - } - return true; - } - - /// - /// Extraction method for solid archives. Uses ExtractAllEntries because extraction for solid archives must be - /// done sequentially, and files beyond a corrupted point in a solid archive will be unreadable anyways. - /// - private static bool ExtractSolid(SevenZipArchive sevenZip, string outDir, bool includeDebug) - { - try - { - if (!Directory.Exists(outDir)) - Directory.CreateDirectory(outDir); - - sevenZip.WriteToDirectory(outDir, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true, - }); - - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } + // Loop through and extract all files + Directory.CreateDirectory(outDir); + sevenZip.Extract(outDir, includeDebug); return true; } -#endif } } \ No newline at end of file diff --git a/BinaryObjectScanner/FileType/TapeArchive.cs b/BinaryObjectScanner/FileType/TapeArchive.cs index 5889845a..2f918362 100644 --- a/BinaryObjectScanner/FileType/TapeArchive.cs +++ b/BinaryObjectScanner/FileType/TapeArchive.cs @@ -1,10 +1,5 @@ -using System; -using System.IO; +using System.IO; using BinaryObjectScanner.Interfaces; -#if NET462_OR_GREATER || NETCOREAPP -using SharpCompress.Archives; -using SharpCompress.Archives.Tar; -#endif namespace BinaryObjectScanner.FileType { @@ -26,65 +21,16 @@ namespace BinaryObjectScanner.FileType /// public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) { - if (stream == null || !stream.CanRead) + // Create the wrapper + var tar = SabreTools.Serialization.Wrappers.TapeArchive.Create(stream); + if (tar == null) return false; -#if NET462_OR_GREATER || NETCOREAPP - try - { - var tarFile = TarArchive.Open(stream); + // Loop through and extract all files + Directory.CreateDirectory(outDir); + tar.Extract(outDir, includeDebug); - // Try to read the file path if no entries are found - if (tarFile.Entries.Count == 0 && !string.IsNullOrEmpty(file) && File.Exists(file)) - tarFile = TarArchive.Open(file); - - foreach (var entry in tarFile.Entries) - { - try - { - // If the entry is a directory - if (entry.IsDirectory) - continue; - - // If the entry has an invalid key - if (entry.Key == null) - continue; - - // If we have a partial entry due to an incomplete multi-part archive, skip it - if (!entry.IsComplete) - continue; - - // Ensure directory separators are consistent - string filename = entry.Key; - if (Path.DirectorySeparatorChar == '\\') - filename = filename.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - filename = filename.Replace('\\', '/'); - - // Ensure the full output directory exists - filename = Path.Combine(outDir, filename); - var directoryName = Path.GetDirectoryName(filename); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - entry.WriteToFile(filename); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } - } - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } -#else - return false; -#endif + return true; } } } diff --git a/BinaryObjectScanner/FileType/VBSP.cs b/BinaryObjectScanner/FileType/VBSP.cs index b7f1fed2..ae2eace1 100644 --- a/BinaryObjectScanner/FileType/VBSP.cs +++ b/BinaryObjectScanner/FileType/VBSP.cs @@ -30,7 +30,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - vbsp.ExtractAllLumps(outDir); + vbsp.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/VPK.cs b/BinaryObjectScanner/FileType/VPK.cs index 7262c55c..32f27576 100644 --- a/BinaryObjectScanner/FileType/VPK.cs +++ b/BinaryObjectScanner/FileType/VPK.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - vpk.ExtractAll(outDir); + vpk.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/WAD3.cs b/BinaryObjectScanner/FileType/WAD3.cs index d31eb2f5..e0932bc2 100644 --- a/BinaryObjectScanner/FileType/WAD3.cs +++ b/BinaryObjectScanner/FileType/WAD3.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - wad.ExtractAllLumps(outDir); + wad.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/FileType/XZ.cs b/BinaryObjectScanner/FileType/XZ.cs index d70eada4..5f0dddd0 100644 --- a/BinaryObjectScanner/FileType/XZ.cs +++ b/BinaryObjectScanner/FileType/XZ.cs @@ -1,9 +1,5 @@ -using System; -using System.IO; +using System.IO; using BinaryObjectScanner.Interfaces; -#if NET462_OR_GREATER || NETCOREAPP -using SharpCompress.Compressors.Xz; -#endif namespace BinaryObjectScanner.FileType { @@ -25,43 +21,16 @@ namespace BinaryObjectScanner.FileType /// public bool Extract(Stream? stream, string file, string outDir, bool includeDebug) { -#if NET462_OR_GREATER || NETCOREAPP - if (stream == null || !stream.CanRead) + // Create the wrapper + var xz = SabreTools.Serialization.Wrappers.XZ.Create(stream); + if (xz == null) return false; - try - { - // Try opening the stream - using var xzFile = new XZStream(stream); + // Loop through and extract all files + Directory.CreateDirectory(outDir); + xz.Extract(outDir, includeDebug); - // Ensure directory separators are consistent - string filename = Guid.NewGuid().ToString(); - if (Path.DirectorySeparatorChar == '\\') - filename = filename.Replace('/', '\\'); - else if (Path.DirectorySeparatorChar == '/') - filename = filename.Replace('\\', '/'); - - // Ensure the full output directory exists - filename = Path.Combine(outDir, filename); - var directoryName = Path.GetDirectoryName(filename); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - // Extract the file - using FileStream fs = File.OpenWrite(filename); - xzFile.CopyTo(fs); - fs.Flush(); - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } -#else - return false; -#endif + return true; } } } diff --git a/BinaryObjectScanner/FileType/XZP.cs b/BinaryObjectScanner/FileType/XZP.cs index 6b91ea2b..0eb49bfc 100644 --- a/BinaryObjectScanner/FileType/XZP.cs +++ b/BinaryObjectScanner/FileType/XZP.cs @@ -28,7 +28,7 @@ namespace BinaryObjectScanner.FileType // Loop through and extract all files Directory.CreateDirectory(outDir); - xzp.ExtractAll(outDir); + xzp.Extract(outDir, includeDebug); return true; } diff --git a/BinaryObjectScanner/Interfaces/IExtractableExecutable.cs b/BinaryObjectScanner/Interfaces/IExtractableExecutable.cs deleted file mode 100644 index df432f24..00000000 --- a/BinaryObjectScanner/Interfaces/IExtractableExecutable.cs +++ /dev/null @@ -1,20 +0,0 @@ -using SabreTools.Serialization.Wrappers; - -namespace BinaryObjectScanner.Interfaces -{ - /// - /// Mark an executable type as being able to be extracted - /// - public interface IExtractableExecutable : IExecutableCheck where T : WrapperBase - { - /// - /// Extract an Executable to a path, if possible - /// - /// Path to the input file - /// Executable representing the read-in file - /// Path to the output directory - /// True to include debug data, false otherwise - /// Path to extracted files, null on error - bool Extract(string file, T exe, string outDir, bool includeDebug); - } -} diff --git a/BinaryObjectScanner/Packer/ASPack.cs b/BinaryObjectScanner/Packer/ASPack.cs index a2d5b3be..623046b7 100644 --- a/BinaryObjectScanner/Packer/ASPack.cs +++ b/BinaryObjectScanner/Packer/ASPack.cs @@ -8,7 +8,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Add extraction // TODO: Research and add support for ASProtect. It seems to be an additional layer of protection for ASPack, making detecting it separately more difficult. - public class ASPack : IExtractableExecutable + public class ASPack : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -49,12 +49,6 @@ namespace BinaryObjectScanner.Packer return null; } - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } - /// /// Generate the set of matchers used for each section /// diff --git a/BinaryObjectScanner/Packer/AdvancedInstaller.cs b/BinaryObjectScanner/Packer/AdvancedInstaller.cs index eb92cf25..1f2335af 100644 --- a/BinaryObjectScanner/Packer/AdvancedInstaller.cs +++ b/BinaryObjectScanner/Packer/AdvancedInstaller.cs @@ -5,7 +5,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Add extraction // TODO: Verify that all versions are detected - public class AdvancedInstaller : IExtractableExecutable + public class AdvancedInstaller : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -20,11 +20,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/AutoPlayMediaStudio.cs b/BinaryObjectScanner/Packer/AutoPlayMediaStudio.cs index df58fcc7..c81df808 100644 --- a/BinaryObjectScanner/Packer/AutoPlayMediaStudio.cs +++ b/BinaryObjectScanner/Packer/AutoPlayMediaStudio.cs @@ -7,7 +7,7 @@ namespace BinaryObjectScanner.Packer // Created by IndigoRose (creators of Setup Factory), primarily to be used to create autorun menus for various media. // Official website: https://www.autoplay.org/ // TODO: Add extraction - public class AutoPlayMediaStudio : IExtractableExecutable + public class AutoPlayMediaStudio : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -25,12 +25,6 @@ namespace BinaryObjectScanner.Packer return null; } - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } - private static string GetVersion(PortableExecutable pex) { // Check the product version explicitly diff --git a/BinaryObjectScanner/Packer/CExe.cs b/BinaryObjectScanner/Packer/CExe.cs index e8c960b2..d70ffe24 100644 --- a/BinaryObjectScanner/Packer/CExe.cs +++ b/BinaryObjectScanner/Packer/CExe.cs @@ -1,8 +1,5 @@ -using System; using System.Collections.Generic; -using System.IO; using BinaryObjectScanner.Interfaces; -using SabreTools.Compression.zlib; using SabreTools.Matching; using SabreTools.Matching.Content; using SabreTools.Serialization.Wrappers; @@ -12,7 +9,7 @@ namespace BinaryObjectScanner.Packer // The official website for CExe also includes the source code (which does have to be retrieved by the Wayback Machine) // http://www.scottlu.com/Content/CExe.html // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class CExe : IExtractableExecutable + public class CExe : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -43,107 +40,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - try - { - // Get all resources of type 99 with index 2 - var resources = pex.FindResourceByNamedType("99, 2"); - if (resources == null || resources.Count == 0) - return false; - - // Get the first resource of type 99 with index 2 - var payload = resources[0]; - if (payload == null || payload.Length == 0) - return false; - - // Create the output data buffer - byte[]? data = []; - - // If we had the decompression DLL included, it's zlib - if (pex.FindResourceByNamedType("99, 1").Count > 0) - { - try - { - // Inflate the data into the buffer - var zstream = new ZLib.z_stream_s(); - data = new byte[payload.Length * 4]; - unsafe - { - fixed (byte* payloadPtr = payload) - fixed (byte* dataPtr = data) - { - zstream.next_in = payloadPtr; - zstream.avail_in = (uint)payload.Length; - zstream.total_in = (uint)payload.Length; - zstream.next_out = dataPtr; - zstream.avail_out = (uint)data.Length; - zstream.total_out = 0; - - ZLib.inflateInit_(zstream, ZLib.zlibVersion(), payload.Length); - int zret = ZLib.inflate(zstream, 1); - ZLib.inflateEnd(zstream); - } - } - - // Trim the buffer to the proper size - uint read = zstream.total_out; -#if NETFRAMEWORK - var temp = new byte[read]; - Array.Copy(data, temp, read); - data = temp; -#else - data = new ReadOnlySpan(data, 0, (int)read).ToArray(); -#endif - } - catch - { - // Reset the data - data = null; - } - } - - // Otherwise, LZ is used - else - { - try - { - var decompressor = SabreTools.Compression.SZDD.Decompressor.CreateSZDD(payload); - var dataStream = new MemoryStream(); - decompressor.CopyTo(dataStream); - data = dataStream.ToArray(); - } - catch - { - // Reset the data - data = null; - } - } - - // If we have no data - if (data == null) - return false; - - // Create the temp filename - string tempFile = string.IsNullOrEmpty(file) ? "temp.sxe" : $"{Path.GetFileNameWithoutExtension(file)}.sxe"; - tempFile = Path.Combine(outDir, tempFile); - var directoryName = Path.GetDirectoryName(tempFile); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - // Write the file data to a temp file - var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); - tempStream.Write(data, 0, data.Length); - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } - } } } diff --git a/BinaryObjectScanner/Packer/Crunch.cs b/BinaryObjectScanner/Packer/Crunch.cs index f30488ff..3b7c1960 100644 --- a/BinaryObjectScanner/Packer/Crunch.cs +++ b/BinaryObjectScanner/Packer/Crunch.cs @@ -6,7 +6,7 @@ namespace BinaryObjectScanner.Packer // Packer used by all known SmartE games, but also used by some other non-SmartE protected software as well. // https://web.archive.org/web/20020806102129/http://www.bit-arts.com/windows_solutions.html // TODO: Other BitArts products may also use this same string. No samples have yet been found. - public class Crunch : IExtractableExecutable + public class Crunch : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -22,11 +22,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/DotFuscator.cs b/BinaryObjectScanner/Packer/DotFuscator.cs index df2d7e10..4be90519 100644 --- a/BinaryObjectScanner/Packer/DotFuscator.cs +++ b/BinaryObjectScanner/Packer/DotFuscator.cs @@ -4,7 +4,7 @@ using SabreTools.Serialization.Wrappers; namespace BinaryObjectScanner.Packer { // TODO: Add extraction - public class DotFuscator : IExtractableExecutable + public class DotFuscator : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -19,11 +19,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/DotNetReactor.cs b/BinaryObjectScanner/Packer/DotNetReactor.cs index e4784910..426197c5 100644 --- a/BinaryObjectScanner/Packer/DotNetReactor.cs +++ b/BinaryObjectScanner/Packer/DotNetReactor.cs @@ -15,7 +15,7 @@ namespace BinaryObjectScanner.Packer /// /// Resource that could be useful for extraction: https://github.com/SychicBoy/NETReactorSlayer /// - public class DotNetReactor : IExtractableExecutable + public class DotNetReactor : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -87,12 +87,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - // TODO: Add extraction - return false; - } } } diff --git a/BinaryObjectScanner/Packer/EXEStealth.cs b/BinaryObjectScanner/Packer/EXEStealth.cs index 2af4de63..e033ba0b 100644 --- a/BinaryObjectScanner/Packer/EXEStealth.cs +++ b/BinaryObjectScanner/Packer/EXEStealth.cs @@ -10,7 +10,7 @@ namespace BinaryObjectScanner.Packer // TODO: Detect 3.15 and up (maybe looking for `Metamorphism`) // TODO: Add extraction // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class EXEStealth : IContentCheck, IExtractableExecutable + public class EXEStealth : IContentCheck, IExecutableCheck { /// public string? CheckContents(string file, byte[] fileContent, bool includeDebug) @@ -62,11 +62,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/EmbeddedArchive.cs b/BinaryObjectScanner/Packer/EmbeddedArchive.cs deleted file mode 100644 index 0007bd07..00000000 --- a/BinaryObjectScanner/Packer/EmbeddedArchive.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System; -using System.IO; -using BinaryObjectScanner.Interfaces; -using SabreTools.Matching; -using SabreTools.Serialization.Wrappers; - -namespace BinaryObjectScanner.Packer -{ - /// - /// Though not technically a packer, this detection is for any executables that include - /// archives in their resources in some uncompressed manner to be used at runtime. - /// - public class EmbeddedArchive : IExtractableExecutable - { - /// - public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) - { - // Get the resources that have a PKZIP signature - if (pex.ResourceData != null) - { - foreach (var value in pex.ResourceData.Values) - { - if (value == null || value is not byte[] ba) - continue; - - if (ba.StartsWith([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C])) - return "Embedded 7-Zip Archive"; - if (ba.StartsWith([0x50, 0x4B, 0x03, 0x04])) - return "Embedded PKZIP Archive"; - if (ba.StartsWith([0x50, 0x4B, 0x05, 0x06])) - return "Embedded PKZIP Archive"; - if (ba.StartsWith([0x50, 0x4B, 0x07, 0x08])) - return "Embedded PKZIP Archive"; - if (ba.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00])) - return "Embedded RAR Archive"; - if (ba.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00])) - return "Embedded RAR Archive"; - } - } - - // Check the overlay, if it exists - if (pex.OverlayData != null && pex.OverlayData.Length > 0) - { - if (pex.OverlayData.StartsWith([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C])) - return "Embedded 7-Zip Archive"; - if (pex.OverlayData.StartsWith([0x50, 0x4B, 0x03, 0x04])) - return "Embedded PKZIP Archive"; - if (pex.OverlayData.StartsWith([0x50, 0x4B, 0x05, 0x06])) - return "Embedded PKZIP Archive"; - if (pex.OverlayData.StartsWith([0x50, 0x4B, 0x07, 0x08])) - return "Embedded PKZIP Archive"; - if (pex.OverlayData.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00])) - return "Embedded RAR Archive"; - if (pex.OverlayData.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00])) - return "Embedded RAR Archive"; - } - - return null; - } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - bool overlay = ExtractFromOverlay(pex, outDir, includeDebug); - bool resources = ExtractFromResources(pex, outDir, includeDebug); - return overlay || resources; - } - - /// - /// Extract archive data from the overlay - /// - private static bool ExtractFromOverlay(PortableExecutable pex, string outDir, bool includeDebug) - { - try - { - // Get the overlay data for easier reading - var overlayData = pex.OverlayData; - if (overlayData == null) - return false; - - // Only process the overlay if it has an archive signature - string extension = string.Empty; - if (overlayData.StartsWith([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C])) - extension = "7z"; - else if (overlayData.StartsWith([0x50, 0x4B, 0x03, 0x04])) - extension = "zip"; - else if (overlayData.StartsWith([0x50, 0x4B, 0x05, 0x06])) - extension = "zip"; - else if (overlayData.StartsWith([0x50, 0x4B, 0x07, 0x08])) - extension = "zip"; - else if (overlayData.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00])) - extension = "rar"; - else if (overlayData.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00])) - extension = "rar"; - else - return false; - - // Create the temp filename - string tempFile = $"embedded_overlay.{extension}"; - tempFile = Path.Combine(outDir, tempFile); - var directoryName = Path.GetDirectoryName(tempFile); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - // Write the resource data to a temp file - using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); - tempStream?.Write(overlayData, 0, overlayData.Length); - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } - } - - /// - /// Extract archive data from the resources - /// - private static bool ExtractFromResources(PortableExecutable pex, string outDir, bool includeDebug) - { - try - { - // If there are no resources - if (pex.ResourceData == null) - return false; - - // Get the resources that have an archive signature - int i = 0; - foreach (var value in pex.ResourceData.Values) - { - if (value == null || value is not byte[] ba) - continue; - - // Only process the resource if it has an archive signature - string extension = string.Empty; - if (ba.StartsWith([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C])) - extension = "7z"; - else if (ba.StartsWith([0x50, 0x4B, 0x03, 0x04])) - extension = "zip"; - else if (ba.StartsWith([0x50, 0x4B, 0x05, 0x06])) - extension = "zip"; - else if (ba.StartsWith([0x50, 0x4B, 0x07, 0x08])) - extension = "zip"; - else if (ba.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00])) - extension = "rar"; - else if (ba.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00])) - extension = "rar"; - else - continue; - - try - { - // Create the temp filename - string tempFile = $"embedded_resource_{i++}.{extension}"; - tempFile = Path.Combine(outDir, tempFile); - var directoryName = Path.GetDirectoryName(tempFile); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - // Write the resource data to a temp file - using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); - tempStream?.Write(ba, 0, ba.Length); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } - } - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } - } - } -} diff --git a/BinaryObjectScanner/Packer/EmbeddedExecutable.cs b/BinaryObjectScanner/Packer/EmbeddedExecutable.cs deleted file mode 100644 index c3026346..00000000 --- a/BinaryObjectScanner/Packer/EmbeddedExecutable.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.IO; -using BinaryObjectScanner.Interfaces; -using SabreTools.Matching; -using SabreTools.Serialization.Wrappers; - -namespace BinaryObjectScanner.Packer -{ - /// - /// Though not technically a packer, this detection is for any executables that include - /// others in their resources in some uncompressed manner to be used at runtime. - /// - public class EmbeddedExecutable : IExtractableExecutable - { - /// - public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) - { - // Get the resources that have an executable signature - if (pex.ResourceData != null) - { - foreach (var value in pex.ResourceData.Values) - { - if (value == null || value is not byte[] ba) - continue; - if (!ba.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes)) - continue; - - return "Embedded Executable"; - } - } - - // Check the overlay, if it exists - if (pex.OverlayData != null && pex.OverlayData.Length > 0) - { - if (pex.OverlayData.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes)) - return "Embedded Executable"; - } - - return null; - } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - bool overlay = ExtractFromOverlay(pex, outDir, includeDebug); - bool resources = ExtractFromResources(pex, outDir, includeDebug); - return overlay || resources; - } - - /// - /// Extract executable data from the overlay - /// - private static bool ExtractFromOverlay(PortableExecutable pex, string outDir, bool includeDebug) - { - try - { - // Get the overlay data for easier reading - var overlayData = pex.OverlayData; - if (overlayData == null) - return false; - - // Only process the overlay if it has an executable signature - if (!overlayData.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes)) - return false; - - // Create the temp filename - string tempFile = $"embedded_overlay.bin"; // exe/dll - tempFile = Path.Combine(outDir, tempFile); - var directoryName = Path.GetDirectoryName(tempFile); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - // Write the resource data to a temp file - using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); - tempStream?.Write(overlayData, 0, overlayData.Length); - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } - } - - /// - /// Extract executable data from the resources - /// - private static bool ExtractFromResources(PortableExecutable pex, string outDir, bool includeDebug) - { - try - { - // If there are no resources - if (pex.ResourceData == null) - return false; - - // Get the resources that have an executable signature - int i = 0; - foreach (var value in pex.ResourceData.Values) - { - if (value == null || value is not byte[] ba) - continue; - if (!ba.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes)) - continue; - - try - { - // Create the temp filename - string tempFile = $"embedded_resource_{i++}.bin"; // exe/dll - tempFile = Path.Combine(outDir, tempFile); - var directoryName = Path.GetDirectoryName(tempFile); - if (directoryName != null && !Directory.Exists(directoryName)) - Directory.CreateDirectory(directoryName); - - // Write the resource data to a temp file - using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); - tempStream?.Write(ba, 0, ba.Length); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - } - } - - return true; - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } - } - } -} diff --git a/BinaryObjectScanner/Packer/EmbeddedFile.cs b/BinaryObjectScanner/Packer/EmbeddedFile.cs new file mode 100644 index 00000000..c538119d --- /dev/null +++ b/BinaryObjectScanner/Packer/EmbeddedFile.cs @@ -0,0 +1,124 @@ +using System; +using BinaryObjectScanner.Interfaces; +using SabreTools.IO.Extensions; +using SabreTools.Matching; +using SabreTools.Serialization.Wrappers; + +namespace BinaryObjectScanner.Packer +{ + /// + /// Though not technically a packer, this detection is for any executables that include + /// archives or executables in their resources in some uncompressed manner to be used at runtime. + /// + public class EmbeddedFile : IExecutableCheck + { + /// + public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) + { + // TODO: Have this return all detected things, not just the first + + // Only process the overlay if it is recognized + if (pex.ResourceData != null) + { + // Cache the resource data for easier reading + var resourceData = pex.ResourceData; + + // Get the resources that have an archive signature + foreach (var value in resourceData.Values) + { + if (value == null || value is not byte[] ba || ba.Length == 0) + continue; + + // Set the output variables + int resourceOffset = 0; + + // Only process the resource if it a recognized signature + for (; resourceOffset < 0x100 && resourceOffset < ba.Length - 0x10; resourceOffset++) + { + int temp = resourceOffset; + byte[] resourceSample = ba.ReadBytes(ref temp, 0x10); + + if (resourceSample.StartsWith([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C])) + return "Embedded 7-Zip Archive"; + else if (resourceSample.StartsWith(SabreTools.Models.MicrosoftCabinet.Constants.SignatureBytes)) + return "Embedded MS-CAB Archive"; + else if (resourceSample.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes)) + return "Embedded PKZIP Archive"; + else if (resourceSample.StartsWith(SabreTools.Models.PKZIP.Constants.EndOfCentralDirectoryRecordSignatureBytes)) + return "Embedded PKZIP Archive"; + else if (resourceSample.StartsWith(SabreTools.Models.PKZIP.Constants.EndOfCentralDirectoryRecord64SignatureBytes)) + return "Embedded PKZIP Archive"; + else if (resourceSample.StartsWith(SabreTools.Models.PKZIP.Constants.DataDescriptorSignatureBytes)) + return "Embedded PKZIP Archive"; + else if (resourceSample.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00])) + return "Embedded RAR Archive"; + else if (resourceSample.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00])) + return "Embedded RAR Archive"; + else if (resourceSample.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes)) + return "Embedded Executable"; + } + } + } + + // Check the overlay, if it exists + if (pex.OverlayData != null && pex.OverlayData.Length > 0) + { + // Set the output variables + int overlayOffset = 0; + + // Only process the overlay if it is recognized + for (; overlayOffset < 0x100 && overlayOffset < pex.OverlayData.Length - 0x10; overlayOffset++) + { + int temp = overlayOffset; + byte[] overlaySample = pex.OverlayData.ReadBytes(ref temp, 0x10); + + if (overlaySample.StartsWith([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C])) + { + return "Embedded 7-Zip Archive"; + } + else if (overlaySample.StartsWith(SabreTools.Models.MicrosoftCabinet.Constants.SignatureBytes)) + { + return "Embedded MS-CAB Archive"; + } + else if (overlaySample.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes)) + { + return "Embedded PKZIP Archive"; + } + else if (overlaySample.StartsWith(SabreTools.Models.PKZIP.Constants.EndOfCentralDirectoryRecordSignatureBytes)) + { + return "Embedded PKZIP Archive"; + } + else if (overlaySample.StartsWith(SabreTools.Models.PKZIP.Constants.EndOfCentralDirectoryRecord64SignatureBytes)) + { + return "Embedded PKZIP Archive"; + } + else if (overlaySample.StartsWith(SabreTools.Models.PKZIP.Constants.DataDescriptorSignatureBytes)) + { + return "Embedded PKZIP Archive"; + } + else if (overlaySample.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00])) + { + return "Embedded RAR Archive"; + } + else if (overlaySample.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00])) + { + return "Embedded RAR Archive"; + } + else if (overlaySample.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes)) + { + return "Embedded Executable"; + } + else if (overlaySample.StartsWith([0x3B, 0x21, 0x40, 0x49, 0x6E, 0x73, 0x74, 0x61, 0x6C, 0x6C])) + { + // 7-zip SFX script -- ";!@Install" to ";!@InstallEnd@!" + overlayOffset = pex.OverlayData.FirstPosition([0x3B, 0x21, 0x40, 0x49, 0x6E, 0x73, 0x74, 0x61, 0x6C, 0x6C, 0x45, 0x6E, 0x64, 0x40, 0x21]); + if (overlayOffset > -1) + return "Embedded 7-Zip Archive"; + } + } + } + + return null; + } + } +} diff --git a/BinaryObjectScanner/Packer/GenteeInstaller.cs b/BinaryObjectScanner/Packer/GenteeInstaller.cs index 5a303041..f983cc31 100644 --- a/BinaryObjectScanner/Packer/GenteeInstaller.cs +++ b/BinaryObjectScanner/Packer/GenteeInstaller.cs @@ -5,7 +5,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Add extraction // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class GenteeInstaller : IExtractableExecutable + public class GenteeInstaller : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -23,11 +23,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/HyperTechCrackProof.cs b/BinaryObjectScanner/Packer/HyperTechCrackProof.cs index 8fec1f89..10c20d28 100644 --- a/BinaryObjectScanner/Packer/HyperTechCrackProof.cs +++ b/BinaryObjectScanner/Packer/HyperTechCrackProof.cs @@ -9,7 +9,7 @@ namespace BinaryObjectScanner.Packer // https://www.reddit.com/r/riseofincarnates/comments/m3vbnm/subreddit_revival_does_anyone_still_have_rise_of/ // https://steamcommunity.com/app/310950/discussions/0/4224890554455490819/ // https://github.com/horsicq/Detect-It-Easy/blob/63a1aa8bb23ca02d8a7fd5936db8dbc5c5d52dea/db/PE/HyperTech%20Crackproof.2.sg - public class HyperTechCrackProof : IExtractableExecutable + public class HyperTechCrackProof : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -24,11 +24,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/InnoSetup.cs b/BinaryObjectScanner/Packer/InnoSetup.cs index 43aa6a67..c9293e03 100644 --- a/BinaryObjectScanner/Packer/InnoSetup.cs +++ b/BinaryObjectScanner/Packer/InnoSetup.cs @@ -8,8 +8,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Add extraction - https://github.com/dscharrer/InnoExtract // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class InnoSetup : IExtractableExecutable, - IExtractableExecutable + public class InnoSetup : IExecutableCheck, IExecutableCheck { /// public string? CheckExecutable(string file, NewExecutable nex, bool includeDebug) @@ -52,18 +51,6 @@ namespace BinaryObjectScanner.Packer return null; } - /// - public bool Extract(string file, NewExecutable nex, string outDir, bool includeDebug) - { - return false; - } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } - private static string GetOldVersion(string file, NewExecutable nex) { // Notes: diff --git a/BinaryObjectScanner/Packer/InstallAnywhere.cs b/BinaryObjectScanner/Packer/InstallAnywhere.cs index 0ee0c623..9f6cbc94 100644 --- a/BinaryObjectScanner/Packer/InstallAnywhere.cs +++ b/BinaryObjectScanner/Packer/InstallAnywhere.cs @@ -6,7 +6,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Add extraction, which may be possible with the current libraries but needs to be investigated further. // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class InstallAnywhere : IExtractableExecutable + public class InstallAnywhere : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -22,12 +22,6 @@ namespace BinaryObjectScanner.Packer return null; } - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } - private static string GetVersion(PortableExecutable pex) { // Check the internal versions diff --git a/BinaryObjectScanner/Packer/InstallerVISE.cs b/BinaryObjectScanner/Packer/InstallerVISE.cs index ee4220db..ed6bb462 100644 --- a/BinaryObjectScanner/Packer/InstallerVISE.cs +++ b/BinaryObjectScanner/Packer/InstallerVISE.cs @@ -5,7 +5,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Add extraction - https://github.com/Bioruebe/UniExtract2 // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class InstallerVISE : IExtractableExecutable + public class InstallerVISE : IExecutableCheck { //TODO: Add exact version detection for Windows builds, make sure versions before 3.X are detected as well, and detect the Mac builds. /// @@ -21,11 +21,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/IntelInstallationFramework.cs b/BinaryObjectScanner/Packer/IntelInstallationFramework.cs index d745d2ad..23d21fdf 100644 --- a/BinaryObjectScanner/Packer/IntelInstallationFramework.cs +++ b/BinaryObjectScanner/Packer/IntelInstallationFramework.cs @@ -5,7 +5,7 @@ using SabreTools.Serialization.Wrappers; namespace BinaryObjectScanner.Packer { // TODO: Add extraction, seems to primarily use MSZip compression. - public class IntelInstallationFramework : IExtractableExecutable + public class IntelInstallationFramework : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -26,11 +26,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/MicrosoftCABSFX.cs b/BinaryObjectScanner/Packer/MicrosoftCABSFX.cs index 234f27c6..b05fd37a 100644 --- a/BinaryObjectScanner/Packer/MicrosoftCABSFX.cs +++ b/BinaryObjectScanner/Packer/MicrosoftCABSFX.cs @@ -6,7 +6,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Add extraction // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class MicrosoftCABSFX : IExtractableExecutable + public class MicrosoftCABSFX : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -40,12 +40,6 @@ namespace BinaryObjectScanner.Packer return null; } - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } - private static string GetVersion(PortableExecutable pex) { // Check the internal versions diff --git a/BinaryObjectScanner/Packer/NSIS.cs b/BinaryObjectScanner/Packer/NSIS.cs index d67c449f..6cdd4f51 100644 --- a/BinaryObjectScanner/Packer/NSIS.cs +++ b/BinaryObjectScanner/Packer/NSIS.cs @@ -4,7 +4,7 @@ using SabreTools.Serialization.Wrappers; namespace BinaryObjectScanner.Packer { // TODO: Add extraction - public class NSIS : IExtractableExecutable + public class NSIS : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -23,11 +23,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } \ No newline at end of file diff --git a/BinaryObjectScanner/Packer/NeoLite.cs b/BinaryObjectScanner/Packer/NeoLite.cs index 37e7adff..abd9e8de 100644 --- a/BinaryObjectScanner/Packer/NeoLite.cs +++ b/BinaryObjectScanner/Packer/NeoLite.cs @@ -13,7 +13,7 @@ namespace BinaryObjectScanner.Packer /// PEiD scanning definitions that include NeoLite: https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt /// Website listing various packers, including NeoLite: http://protools.narod.ru/packers.htm /// - public class NeoLite : IExtractableExecutable + public class NeoLite : IExecutableCheck { // TODO: Find samples of NeoLite 1.X. /// @@ -28,11 +28,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/PECompact.cs b/BinaryObjectScanner/Packer/PECompact.cs index 562661ed..b296cc89 100644 --- a/BinaryObjectScanner/Packer/PECompact.cs +++ b/BinaryObjectScanner/Packer/PECompact.cs @@ -5,7 +5,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Better version detection - https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt // TODO: Add extraction - public class PECompact : IExtractableExecutable + public class PECompact : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -33,11 +33,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/PEtite.cs b/BinaryObjectScanner/Packer/PEtite.cs index f551db7b..ef8c103d 100644 --- a/BinaryObjectScanner/Packer/PEtite.cs +++ b/BinaryObjectScanner/Packer/PEtite.cs @@ -5,7 +5,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Add extraction // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class PEtite : IExtractableExecutable + public class PEtite : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -16,11 +16,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/SetupFactory.cs b/BinaryObjectScanner/Packer/SetupFactory.cs index e23dc81c..c18c321f 100644 --- a/BinaryObjectScanner/Packer/SetupFactory.cs +++ b/BinaryObjectScanner/Packer/SetupFactory.cs @@ -7,7 +7,7 @@ namespace BinaryObjectScanner.Packer // TODO: Add extraction, which is possible but the only tools available that can // do this seem to be Universal Extractor 2 and InstallExplorer (https://totalcmd.net/plugring/InstallExplorer.html) // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class SetupFactory : IExtractableExecutable + public class SetupFactory : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -32,12 +32,6 @@ namespace BinaryObjectScanner.Packer return null; } - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } - private static string GetVersion(PortableExecutable pex) { // Check the product version explicitly diff --git a/BinaryObjectScanner/Packer/SevenZipSFX.cs b/BinaryObjectScanner/Packer/SevenZipSFX.cs index b0f87cbb..e35879cb 100644 --- a/BinaryObjectScanner/Packer/SevenZipSFX.cs +++ b/BinaryObjectScanner/Packer/SevenZipSFX.cs @@ -3,7 +3,7 @@ using SabreTools.Serialization.Wrappers; namespace BinaryObjectScanner.Packer { - public class SevenZipSFX : IExtractableExecutable + public class SevenZipSFX : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -36,12 +36,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - var sevenZip = new FileType.SevenZip(); - return sevenZip.Extract(file, outDir, lookForHeader: true, includeDebug); - } } } diff --git a/BinaryObjectScanner/Packer/Shrinker.cs b/BinaryObjectScanner/Packer/Shrinker.cs index 7a8e15f7..d7241df6 100644 --- a/BinaryObjectScanner/Packer/Shrinker.cs +++ b/BinaryObjectScanner/Packer/Shrinker.cs @@ -5,7 +5,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Add extraction // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class Shrinker : IExtractableExecutable + public class Shrinker : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -16,11 +16,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/Packer/UPX.cs b/BinaryObjectScanner/Packer/UPX.cs index d7aea595..926d440f 100644 --- a/BinaryObjectScanner/Packer/UPX.cs +++ b/BinaryObjectScanner/Packer/UPX.cs @@ -8,7 +8,7 @@ namespace BinaryObjectScanner.Packer { // TODO: Add extraction // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class UPX : IExtractableExecutable + public class UPX : IExecutableCheck { private static readonly Regex _oldUpxVersionMatch = new Regex(@"\$Id: UPX (.*?) Copyright \(C\)", RegexOptions.Compiled); @@ -56,12 +56,6 @@ namespace BinaryObjectScanner.Packer return null; } - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } - public static string GetVersion(string file, byte[] fileContent, List positions) { try diff --git a/BinaryObjectScanner/Packer/WinRARSFX.cs b/BinaryObjectScanner/Packer/WinRARSFX.cs index c24b8035..e19e0fa3 100644 --- a/BinaryObjectScanner/Packer/WinRARSFX.cs +++ b/BinaryObjectScanner/Packer/WinRARSFX.cs @@ -3,7 +3,7 @@ using SabreTools.Serialization.Wrappers; namespace BinaryObjectScanner.Packer { - public class WinRARSFX : IExtractableExecutable + public class WinRARSFX : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -17,12 +17,5 @@ namespace BinaryObjectScanner.Packer return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - var rar = new FileType.RAR(); - return rar.Extract(file, outDir, lookForHeader: true, includeDebug); - } } } diff --git a/BinaryObjectScanner/Packer/WinZipSFX.cs b/BinaryObjectScanner/Packer/WinZipSFX.cs index f0d6370e..ec094d16 100644 --- a/BinaryObjectScanner/Packer/WinZipSFX.cs +++ b/BinaryObjectScanner/Packer/WinZipSFX.cs @@ -5,7 +5,7 @@ using SabreTools.Serialization.Wrappers; namespace BinaryObjectScanner.Packer { - public class WinZipSFX : IExtractableExecutable, IExtractableExecutable + public class WinZipSFX : IExecutableCheck, IExecutableCheck { /// public string? CheckExecutable(string file, NewExecutable nex, bool includeDebug) @@ -56,23 +56,6 @@ namespace BinaryObjectScanner.Packer // TODO: Find a way to generically detect 2.X versions and improve exact version detection for SFX PE versions bundled with WinZip 11+ - /// - public bool Extract(string file, NewExecutable nex, string outDir, bool includeDebug) - => Extract(file, outDir, includeDebug); - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - => Extract(file, outDir, includeDebug); - - /// - /// Handle common extraction between executable types - /// - public static bool Extract(string file, string outDir, bool includeDebug) - { - var pkzip = new FileType.PKZIP(); - return pkzip.Extract(file, outDir, lookForHeader: true, includeDebug); - } - /// /// Get the version from the NE header value combinations /// diff --git a/BinaryObjectScanner/Packer/WiseInstaller.cs b/BinaryObjectScanner/Packer/WiseInstaller.cs index d3fbf2c8..253a5d90 100644 --- a/BinaryObjectScanner/Packer/WiseInstaller.cs +++ b/BinaryObjectScanner/Packer/WiseInstaller.cs @@ -1,155 +1,33 @@ using System; -using System.Collections.Generic; using System.IO; using BinaryObjectScanner.Interfaces; -using SabreTools.Matching; -using SabreTools.Matching.Content; using SabreTools.Serialization.Wrappers; -using WiseUnpacker; -using WiseUnpacker.EWISE; namespace BinaryObjectScanner.Packer { // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class WiseInstaller : IExtractableExecutable, IExtractableExecutable + public class WiseInstaller : IExecutableCheck, IExecutableCheck { /// public string? CheckExecutable(string file, NewExecutable nex, bool includeDebug) { - // If we match a known header - if (MatchesNEVersion(nex) != null) + // If the overlay header can be found + if (nex.FindWiseOverlayHeader() > -1) return "Wise Installation Wizard Module"; - // TODO: Investigate STUB.EXE in nonresident-name table - - // TODO: Don't read entire file - var data = nex.ReadArbitraryRange(); - if (data == null) - return null; - - var neMatchSets = new List - { - // WiseInst - new(new byte?[] { 0x57, 0x69, 0x73, 0x65, 0x49, 0x6E, 0x73, 0x74 }, "Wise Installation Wizard Module"), - - // WiseMain - new(new byte?[] { 0x57, 0x69, 0x73, 0x65, 0x4D, 0x61, 0x69, 0x6E }, "Wise Installation Wizard Module"), - }; - - return MatchUtil.GetFirstMatch(file, data, neMatchSets, includeDebug); + return null; } /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) { - // If we match a known header - if (GetPEFormat(pex) != null) + // If the overlay header can be found + if (pex.FindWiseOverlayHeader() > -1) return "Wise Installation Wizard Module"; - // TODO: Investigate STUB32.EXE in export directory table - - // Get the .data/DATA section strings, if they exist - var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA"); - if (strs != null) - { - if (strs.Exists(s => s.Contains("WiseMain"))) - return "Wise Installation Wizard Module"; - } - - // Get the .rdata section strings, if they exist - strs = pex.GetFirstSectionStrings(".rdata"); - if (strs != null) - { - if (strs.Exists(s => s.Contains("WiseMain"))) - return "Wise Installation Wizard Module"; - } - - return null; - } - - /// - public bool Extract(string file, NewExecutable nex, string outDir, bool includeDebug) - { - try - { - Directory.CreateDirectory(outDir); - return Extractor.ExtractTo(file, outDir); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } - } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - try - { - Directory.CreateDirectory(outDir); - return Extractor.ExtractTo(file, outDir); - } - catch (Exception ex) - { - if (includeDebug) Console.Error.WriteLine(ex); - return false; - } - } - - /// - /// Checks an NE header to see if it matches a known signature - /// - /// New executable to check - /// True if it matches a known version, false otherwise - private static FormatProperty? MatchesNEVersion(NewExecutable nex) - { - // TODO: Offset is _not_ the EXE header address, rather where the data starts. Fix this. - return (nex.Model.Stub?.Header?.NewExeHeaderAddr) switch - { - 0x84b0 => new FormatProperty { ArchiveEnd = -1 }, - 0x3e10 => new FormatProperty { ArchiveEnd = -1 }, - 0x3e50 => new FormatProperty { ArchiveEnd = -1 }, - 0x3c20 => new FormatProperty { ArchiveEnd = -1 }, - 0x3c30 => new FormatProperty { ArchiveEnd = -1 }, - 0x3660 => new FormatProperty { ArchiveEnd = 0x3c }, - 0x36f0 => new FormatProperty { ArchiveEnd = 0x44 }, - 0x3770 => new FormatProperty { ArchiveEnd = 0x4c }, - 0x3780 => new FormatProperty { ArchiveEnd = 0x4c }, - 0x37b0 => new FormatProperty { ArchiveEnd = 0x4c }, - 0x37d0 => new FormatProperty { ArchiveEnd = 0x4c }, - 0x3c80 => new FormatProperty { ArchiveEnd = 0x4c }, - 0x3bd0 => new FormatProperty { ArchiveEnd = 0x4c }, - 0x3c10 => new FormatProperty { ArchiveEnd = 0x4c }, - _ => null, - }; - } - - /// - /// Checks a PE header to see if it matches a known signature - /// - /// Portable executable to check - /// True if it matches a known version, false otherwise - private static FormatProperty? GetPEFormat(PortableExecutable pex) - { - // Get the current format - var current = new FormatProperty - { - ExecutableType = ExecutableType.PE, - CodeSectionLength = (int?)pex.GetFirstSection(".text")?.VirtualSize ?? -1, - DataSectionLength = (int?)pex.GetFirstSection(".data")?.VirtualSize ?? -1, - }; - - // Search known formats - foreach (var format in FormatProperty.KnownFormats) - { - if (current.Equals(format)) - return format; - } - - // Found in Binary.WiseCustomCalla - if (pex.OverlayAddress == 0x6200) - return new FormatProperty { ArchiveEnd = 0x4c }; + // If the section header can be found + if (pex.FindWiseSection() != null) + return "Wise Installation Wizard Module"; return null; } diff --git a/BinaryObjectScanner/Protection/Armadillo.cs b/BinaryObjectScanner/Protection/Armadillo.cs index 658a6f23..4cd5cc2a 100644 --- a/BinaryObjectScanner/Protection/Armadillo.cs +++ b/BinaryObjectScanner/Protection/Armadillo.cs @@ -18,7 +18,7 @@ namespace BinaryObjectScanner.Protection // TODO: Add version checking, if possible // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt - public class Armadillo : IExtractableExecutable + public class Armadillo : IExecutableCheck { /// public string? CheckExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -44,11 +44,5 @@ namespace BinaryObjectScanner.Protection return null; } - - /// - public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) - { - return false; - } } } diff --git a/BinaryObjectScanner/_EXTERNAL/README.MD b/BinaryObjectScanner/_EXTERNAL/README.MD deleted file mode 100644 index 1dab0038..00000000 --- a/BinaryObjectScanner/_EXTERNAL/README.MD +++ /dev/null @@ -1,7 +0,0 @@ -# External Library Notes - -This directory contains multiple external libraries. Here is the status of each: - -| Directory | Library | Status | -| --------- | ------- | ------ | -| stormlibsharp | [stormlibsharp](https://github.com/robpaveza/stormlibsharp) | External submodule | diff --git a/BinaryObjectScanner/_EXTERNAL/stormlibsharp b/BinaryObjectScanner/_EXTERNAL/stormlibsharp deleted file mode 160000 index 3bf13753..00000000 --- a/BinaryObjectScanner/_EXTERNAL/stormlibsharp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3bf13753171d8d1e430f5f044fcbc10b1fd7089f diff --git a/BinaryObjectScanner/runtimes/win-x64/native/CascLib.dll b/BinaryObjectScanner/runtimes/win-x64/native/CascLib.dll deleted file mode 100644 index cc5b7a4f..00000000 Binary files a/BinaryObjectScanner/runtimes/win-x64/native/CascLib.dll and /dev/null differ diff --git a/BinaryObjectScanner/runtimes/win-x64/native/StormLib.dll b/BinaryObjectScanner/runtimes/win-x64/native/StormLib.dll deleted file mode 100644 index afbe72a5..00000000 Binary files a/BinaryObjectScanner/runtimes/win-x64/native/StormLib.dll and /dev/null differ diff --git a/BinaryObjectScanner/runtimes/win-x86/native/CascLib.dll b/BinaryObjectScanner/runtimes/win-x86/native/CascLib.dll deleted file mode 100644 index e4b4ff14..00000000 Binary files a/BinaryObjectScanner/runtimes/win-x86/native/CascLib.dll and /dev/null differ diff --git a/BinaryObjectScanner/runtimes/win-x86/native/StormLib.dll b/BinaryObjectScanner/runtimes/win-x86/native/StormLib.dll deleted file mode 100644 index ff0700b9..00000000 Binary files a/BinaryObjectScanner/runtimes/win-x86/native/StormLib.dll and /dev/null differ diff --git a/Coding Guide.md b/Coding Guide.md index 52cd6c76..74f938d4 100644 --- a/Coding Guide.md +++ b/Coding Guide.md @@ -378,10 +378,10 @@ Typed checks, such as `IExecutableCheck` should always follow this order: `MS | --- | --- | | `BinaryObjectScanner` | Varies from file to file. | | `BinaryObjectScanner/FileType` | `IDetectable` implementations, `IExtractable` implementations, helper methods. | -| `BinaryObjectScanner/GameEngine` | `IContentCheck` implementations, `IExecutableCheck` implementations, `IPathCheck` implementations, `IExtractableExecutable` implementations, helper methods. | +| `BinaryObjectScanner/GameEngine` | `IContentCheck` implementations, `IExecutableCheck` implementations, `IPathCheck` implementations, helper methods. | | `BinaryObjectScanner/Interfaces` | Methods ordered alphabetically. | -| `BinaryObjectScanner/Packer` | `IContentCheck` implementations, `IExecutableCheck` implementations, `IPathCheck` implementations, `IExtractableExecutable` implementations, helper methods. | -| `BinaryObjectScanner/Protection` | `IContentCheck` implementations, `IExecutableCheck` implementations, `IPathCheck` implementations, `IExtractableExecutable` implementations, helper methods. | +| `BinaryObjectScanner/Packer` | `IContentCheck` implementations, `IExecutableCheck` implementations, `IPathCheck` implementations, helper methods. | +| `BinaryObjectScanner/Protection` | `IContentCheck` implementations, `IExecutableCheck` implementations, `IPathCheck` implementations, helper methods. | | `ProtectionScan` | New functionality should be added as a combination of a flag with a long and a short form, a new line in the help text, and a new method (if necessary). | If the project or directory you are looking for is not included in the above, please consider it to be outside the context of this document. diff --git a/Developer Guide.md b/Developer Guide.md index 375cb73a..ac9d3905 100644 --- a/Developer Guide.md +++ b/Developer Guide.md @@ -35,18 +35,16 @@ Adding a new checker or format should happen in a few distinct steps: - If it is a new supported file type (such as an archive format), create the file in `BinaryObjectScanner.FileType`. By default, you will need to implement `BinaryObjectScanner.Interfaces.IDetectable` or `BinaryObjectScanner.Interfaces.IExtractable`. Do not implement any other interfaces. Please consider asking project maintainers before doing this work, especially if there are external dependencies. - - If it is a new supported game engine or standard library, create the file in `BinaryObjectScanner.GameEngine`. By default, you will need to implement `BinaryObjectScanner.Interfaces.IExecutableCheck` or `BinaryObjectScanner.Interfaces.IExtractableExecutable`. It is exceptionally rare to need to implement `BinaryObjectScanner.Interfaces.IPathCheck`. + - If it is a new supported game engine or standard library, create the file in `BinaryObjectScanner.GameEngine`. By default, you will need to implement `BinaryObjectScanner.Interfaces.IExecutableCheck`. It is exceptionally rare to need to implement `BinaryObjectScanner.Interfaces.IPathCheck`. - - If it is a new supported executable packer, compressor, or installer format, create the file in `BinaryObjectScanner.Packer`. By default, you will need to implement at least one of: `BinaryObjectScanner.Interfaces.IExtractableExecutable`. It is exceptionally rare to need to implement `BinaryObjectScanner.Interfaces.IPathCheck`. + - If it is a new supported executable packer, compressor, or installer format, create the file in `BinaryObjectScanner.Packer`. By default, you will need to implement a new Wrapper in `SabreTools.Serialization.Wrappers`. It is exceptionally rare to need to implement `BinaryObjectScanner.Interfaces.IPathCheck`. - - If it is a new supported DRM scheme, copy protection, or obfuscator, create the file in `BinaryObjectScanner.Protection`. By default, you will need to implement at least one of: `BinaryObjectScanner.Interfaces.IExecutableCheck`, `BinaryObjectScanner.Interfaces.IExtractableExecutable`, or `BinaryObjectScanner.Interfaces.IPathCheck`. + - If it is a new supported DRM scheme, copy protection, or obfuscator, create the file in `BinaryObjectScanner.Protection`. By default, you will need to implement at least one of: `BinaryObjectScanner.Interfaces.IExecutableCheck` or `BinaryObjectScanner.Interfaces.IPathCheck`. - In addition to the above, there is a debug-only interface called `BinaryObjectScanner.Interfaces.IContentCheck`. Though there are examples of this being used in code, it is highly recommended to avoid this in a final implementation. - Typed executable checks, such as `IExecutableCheck` should always follow this order: `MSDOS`, `LinearExecutable`, `NewExecutable`, `PortableExecutable`. - - If both `IExecutableCheck` and `IExtractableExecutable` are needed, only `IExtractableExecutable` is required because it extends from `IExecutableCheck`. - 2. Look at other, similar classes for guidelines on how any given set of checks should be implemented. Test early and often, including using debugging tools. Err on the side of over-commenting. Do not try to be clever with your code; readable code is royalty. 3. Unless otherwise directed to by a maintainer, the only way to get changes in is through a pull request on GitHub. We do not accept patches in the form of patchfiles or archives. Please note that the maintainers may need an increased amount of time to review for obscure or hard-to-find protections. diff --git a/README.md b/README.md index 0f78d60d..08b8f13e 100644 --- a/README.md +++ b/README.md @@ -149,8 +149,7 @@ Below is a list of executable packers detected by BinaryObjectScanner. The three | AutoPlay Media Studio | Yes | No | No | | | CExe | Yes | No | Yes | | | dotFuscator | Yes | No | No | | -| Embedded Archive | Yes | No | Yes | Not technically a packer | -| Embedded Executable | Yes | No | Yes | Not technically a packer | +| Embedded File | Yes | No | Yes | Not technically a packer | | EXE Stealth | Yes | No | No | | | Gentee Installer | Yes | No | No | | | HyperTech CrackProof | Yes | No | No | |