diff --git a/BinaryObjectScanner/Packer/EmbeddedArchive.cs b/BinaryObjectScanner/Packer/EmbeddedArchive.cs new file mode 100644 index 00000000..9857faaa --- /dev/null +++ b/BinaryObjectScanner/Packer/EmbeddedArchive.cs @@ -0,0 +1,85 @@ +using System; +using System.IO; +using System.Linq; +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 sections from the executable, if possible + var sections = pex.Model.SectionTable; + if (sections == null) + return null; + + // Get the resources that have a PKZIP signature + if (pex.ResourceData?.Any(kvp => kvp.Value is byte[] ba + && ba.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes)) == true) + { + return "Embedded Archive"; + } + + return null; + } + + /// + public bool Extract(string file, PortableExecutable pex, string outDir, bool includeDebug) + { + try + { + // If there are no resources + if (pex.ResourceData == null) + return false; + + // Get the resources that have a PKZIP signature + var resources = pex.ResourceData + .Where(kvp => kvp.Value != null && kvp.Value is byte[]) + .Select(kvp => kvp.Value as byte[]) + .Where(b => b != null && b.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes)) + .ToList(); + + for (int i = 0; i < resources.Count; i++) + { + try + { + // Get the resource data + var data = resources[i]; + if (data == null) + continue; + + // Create the temp filename + string tempFile = $"embedded_resource_{i}.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(data, 0, data.Length); + } + catch (Exception ex) + { + if (includeDebug) Console.WriteLine(ex); + } + } + + return true; + } + catch (Exception ex) + { + if (includeDebug) Console.WriteLine(ex); + return false; + } + } + } +} diff --git a/README.md b/README.md index d55d68ea..c4467ce6 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,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 | | EXE Stealth | Yes | No | No | | | Gentee Installer | Yes | No | No | |