diff --git a/BurnOutSharp/PackerType/UPX.cs b/BurnOutSharp/PackerType/UPX.cs index e8c1bce3..a5bdf03c 100644 --- a/BurnOutSharp/PackerType/UPX.cs +++ b/BurnOutSharp/PackerType/UPX.cs @@ -1,53 +1,60 @@ using System.Collections.Generic; +using System.Linq; using System.Text; +using BurnOutSharp.ExecutableType.Microsoft; using BurnOutSharp.Matching; +using BurnOutSharp.Tools; namespace BurnOutSharp.PackerType { public class UPX : IContentCheck { /// - public List GetContentMatchSets() - { - return new List - { - // UPX! - new ContentMatchSet(new byte?[] { 0x55, 0x50, 0x58, 0x21 }, GetVersion, "UPX"), - - // NOS - new ContentMatchSet( - new ContentMatch(new byte?[] { 0x4E, 0x4F, 0x53, 0x20 }, end: 2048), - GetVersion, - "UPX (NOS Variant)"), - - new ContentMatchSet( - new List - { - // UPX0 - new byte?[] { 0x55, 0x50, 0x58, 0x30 }, - - // UPX1 - new byte?[] { 0x55, 0x50, 0x58, 0x31 }, - }, - "UPX (Unknown Version)" - ), - - new ContentMatchSet( - new List - { - // NOS0 - new byte?[] { 0x4E, 0x4F, 0x53, 0x30 }, - - // NOS1 - new byte?[] { 0x4E, 0x4F, 0x53, 0x31 }, - }, - "UPX (NOS Variant) (Unknown Version)" - ), - }; - } + public List GetContentMatchSets() => null; /// - public string CheckContents(string file, byte[] fileContent, bool includeDebug = false) => null; + public string CheckContents(string file, byte[] fileContent, bool includeDebug = false) + { + // Get the sections from the executable, if possible + PEExecutable pex = PEExecutable.Deserialize(fileContent, 0); + var sections = pex?.SectionHeaders; + if (sections == null) + return null; + + // Standard UPX + int foundPosition = FindData(fileContent, sections, "UPX"); + if (foundPosition > -1) + { + var matchers = new List + { + // UPX! + new ContentMatchSet( + new ContentMatch(new byte?[] { 0x55, 0x50, 0x58, 0x21 }, end: foundPosition), + GetVersion, + "UPX"), + }; + + return MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug); + } + + // NOS Variant + foundPosition = FindData(fileContent, sections, "NOS"); + if (foundPosition > -1) + { + var matchers = new List + { + // NOS + new ContentMatchSet( + new ContentMatch(new byte?[] { 0x4E, 0x4F, 0x53, 0x20 }, end: foundPosition), + GetVersion, + "UPX (NOS Variant)"), + }; + + return MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug); + } + + return null; + } public static string GetVersion(string file, byte[] fileContent, List positions) { @@ -66,5 +73,26 @@ namespace BurnOutSharp.PackerType return "(Unknown Version)"; } } + + /// + /// Find the location of the first matched section, if possible + /// + /// Byte array representing the file contents + /// Array of sections to check against + /// Prefix of the sections to check for + /// Real address of the section data, -1 on error + private int FindData(byte[] fileContent, IMAGE_SECTION_HEADER[] sections, string sectionPrefix) + { + // Get the two matching sections, if possible + var firstSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith($"{sectionPrefix}0")); + var secondSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith($"{sectionPrefix}1")); + + // If either section is null, we can't do anything + if (firstSection == null || secondSection == null) + return -1; + + // Return the first section address + return (int)EVORE.ConvertVirtualAddress(firstSection.VirtualAddress, sections); + } } } \ No newline at end of file