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 | |