diff --git a/BinaryObjectScanner/Packer/EmbeddedArchive.cs b/BinaryObjectScanner/Packer/EmbeddedArchive.cs index 877ed5b0..63635e9c 100644 --- a/BinaryObjectScanner/Packer/EmbeddedArchive.cs +++ b/BinaryObjectScanner/Packer/EmbeddedArchive.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using BinaryObjectScanner.Interfaces; using SabreTools.Matching; using SabreTools.Serialization.Wrappers; @@ -22,11 +21,24 @@ namespace BinaryObjectScanner.Packer return null; // Get the resources that have a PKZIP signature - if (pex.ResourceData != null - && pex.ResourceData.Values.Any(v => v is byte[] ba - && ba.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))) + if (pex.ResourceData != null) { - return "Embedded Archive"; + foreach (var value in pex.ResourceData.Values) + { + if (value == null || value is not byte[] ba) + continue; + if (!ba.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes)) + continue; + + return "Embedded Archive"; + } + } + + // Check the overlay, if it exists + if (pex.OverlayData != null && pex.OverlayData.Length > 0) + { + if (pex.OverlayData.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes)) + return "Embedded Archive"; } return null; @@ -34,6 +46,52 @@ namespace BinaryObjectScanner.Packer /// 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 + if (!overlayData.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes)) + return false; + + // Create the temp filename + string tempFile = $"embedded_overlay.zip"; + 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.WriteLine(ex); + return false; + } + } + + /// + /// Extract archive data from the resources + /// + private static bool ExtractFromResources(PortableExecutable pex, string outDir, bool includeDebug) { try { @@ -41,24 +99,19 @@ namespace BinaryObjectScanner.Packer if (pex.ResourceData == null) return false; - // Get the resources that have a PKZIP signature - var resources = pex.ResourceData.Values - .Where(v => v != null && v is byte[]) - .Select(v => v as byte[]) - .Where(b => b != null && b.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes)) - .ToList(); - - for (int i = 0; i < resources.Count; i++) + // 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; + if (!ba.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes)) + continue; + try { - // Get the resource data - var data = resources[i]; - if (data == null) - continue; - // Create the temp filename - string tempFile = $"embedded_resource_{i}.zip"; + string tempFile = $"embedded_resource_{i++}.zip"; tempFile = Path.Combine(outDir, tempFile); var directoryName = Path.GetDirectoryName(tempFile); if (directoryName != null && !Directory.Exists(directoryName)) @@ -66,7 +119,7 @@ namespace BinaryObjectScanner.Packer // Write the resource data to a temp file using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); - tempStream?.Write(data, 0, data.Length); + tempStream?.Write(ba, 0, ba.Length); } catch (Exception ex) { diff --git a/BinaryObjectScanner/Packer/EmbeddedExecutable.cs b/BinaryObjectScanner/Packer/EmbeddedExecutable.cs index 11dd568e..33309448 100644 --- a/BinaryObjectScanner/Packer/EmbeddedExecutable.cs +++ b/BinaryObjectScanner/Packer/EmbeddedExecutable.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using BinaryObjectScanner.Interfaces; using SabreTools.Matching; using SabreTools.Serialization.Wrappers; @@ -22,11 +21,24 @@ namespace BinaryObjectScanner.Packer return null; // Get the resources that have an executable signature - if (pex.ResourceData != null - && pex.ResourceData.Values.Any(v => v is byte[] ba - && ba.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes))) + if (pex.ResourceData != null) { - return "Embedded Executable"; + 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; @@ -34,6 +46,52 @@ namespace BinaryObjectScanner.Packer /// 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.WriteLine(ex); + return false; + } + } + + /// + /// Extract executable data from the resources + /// + private static bool ExtractFromResources(PortableExecutable pex, string outDir, bool includeDebug) { try { @@ -42,23 +100,18 @@ namespace BinaryObjectScanner.Packer return false; // Get the resources that have an executable signature - var resources = pex.ResourceData.Values - .Where(v => v != null && v is byte[]) - .Select(v => v as byte[]) - .Where(b => b != null && b.StartsWith(SabreTools.Models.MSDOS.Constants.SignatureBytes)) - .ToList(); - - for (int i = 0; i < resources.Count; i++) + 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 { - // Get the resource data - var data = resources[i]; - if (data == null) - continue; - // Create the temp filename - string tempFile = $"embedded_resource_{i}.bin"; + string tempFile = $"embedded_resource_{i++}.bin"; // exe/dll tempFile = Path.Combine(outDir, tempFile); var directoryName = Path.GetDirectoryName(tempFile); if (directoryName != null && !Directory.Exists(directoryName)) @@ -66,7 +119,7 @@ namespace BinaryObjectScanner.Packer // Write the resource data to a temp file using var tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); - tempStream?.Write(data, 0, data.Length); + tempStream?.Write(ba, 0, ba.Length); } catch (Exception ex) {