diff --git a/BurnOutSharp/ExecutableType/Microsoft/NewExecutable.cs b/BurnOutSharp/ExecutableType/Microsoft/NewExecutable.cs
index 33c6d5d2..99923831 100644
--- a/BurnOutSharp/ExecutableType/Microsoft/NewExecutable.cs
+++ b/BurnOutSharp/ExecutableType/Microsoft/NewExecutable.cs
@@ -10,6 +10,21 @@ namespace BurnOutSharp.ExecutableType.Microsoft
///
public class NewExecutable
{
+ ///
+ /// Value determining if the executable is initialized or not
+ ///
+ public bool Initialized { get; } = false;
+
+ ///
+ /// Source array that the executable was parsed from
+ ///
+ public byte[] SourceArray { get; } = null;
+
+ ///
+ /// Source stream that the executable was parsed from
+ ///
+ public Stream SourceStream { get; } = null;
+
#region Headers
///
@@ -28,70 +43,109 @@ namespace BurnOutSharp.ExecutableType.Microsoft
#endregion
+ #region Constructors
+
// TODO: Add more and more parts of a standard NE executable, not just the header
// TODO: Tables? What about the tables?
// TODO: Implement the rest of the structures found at http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm
// (Left off at RESIDENT-NAME TABLE)
- public static NewExecutable Deserialize(Stream stream)
+ ///
+ /// Create a NewExecutable object from a stream
+ ///
+ /// Stream representing a file
+ ///
+ /// This constructor assumes that the stream is already in the correct position to start parsing
+ ///
+ public NewExecutable(Stream stream)
{
- NewExecutable nex = new NewExecutable();
+ if (stream == null || !stream.CanRead || !stream.CanSeek)
+ return;
+ this.Initialized = Deserialize(stream);
+ this.SourceStream = stream;
+ }
+
+ ///
+ /// Create a NewExecutable object from a byte array
+ ///
+ /// Byte array representing a file
+ /// Positive offset representing the current position in the array
+ public NewExecutable(byte[] fileContent, int offset)
+ {
+ if (fileContent == null || fileContent.Length == 0 || offset < 0)
+ return;
+
+ this.Initialized = Deserialize(fileContent, offset);
+ this.SourceArray = fileContent;
+ }
+
+ ///
+ /// Deserialize a NewExecutable object from a stream
+ ///
+ /// Stream representing a file
+ private bool Deserialize(Stream stream)
+ {
try
{
// Attempt to read the DOS header first
- nex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream);
- stream.Seek(nex.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
- if (nex.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
- return null;
+ this.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream);
+ stream.Seek(this.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
+ if (this.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
+ return false;
// If the new header address is invalid for the file, it's not a NE
- if (nex.DOSStubHeader.NewExeHeaderAddr >= stream.Length)
- return null;
+ if (this.DOSStubHeader.NewExeHeaderAddr >= stream.Length)
+ return false;
// Then attempt to read the NE header
- nex.NewExecutableHeader = NewExecutableHeader.Deserialize(stream);
- if (nex.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
- return null;
+ this.NewExecutableHeader = NewExecutableHeader.Deserialize(stream);
+ if (this.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
+ return false;
}
catch (Exception ex)
{
//Console.WriteLine($"Errored out on a file: {ex}");
- return null;
+ return false;
}
- return nex;
+ return true;
}
- public static NewExecutable Deserialize(byte[] content, int offset)
+ ///
+ /// Deserialize a NewExecutable object from a byte array
+ ///
+ /// Byte array representing a file
+ /// Positive offset representing the current position in the array
+ private bool Deserialize(byte[] content, int offset)
{
- NewExecutable nex = new NewExecutable();
-
try
{
// Attempt to read the DOS header first
- nex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, ref offset);
- offset = nex.DOSStubHeader.NewExeHeaderAddr;
- if (nex.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
- return null;
+ this.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, ref offset);
+ offset = this.DOSStubHeader.NewExeHeaderAddr;
+ if (this.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
+ return false;
// If the new header address is invalid for the file, it's not a PE
- if (nex.DOSStubHeader.NewExeHeaderAddr >= content.Length)
- return null;
+ if (this.DOSStubHeader.NewExeHeaderAddr >= content.Length)
+ return false;
// Then attempt to read the NE header
- nex.NewExecutableHeader = NewExecutableHeader.Deserialize(content, ref offset);
- if (nex.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
- return null;
+ this.NewExecutableHeader = NewExecutableHeader.Deserialize(content, ref offset);
+ if (this.NewExecutableHeader.Magic != Constants.IMAGE_OS2_SIGNATURE)
+ return false;
}
catch (Exception ex)
{
//Console.WriteLine($"Errored out on a file: {ex}");
- return null;
+ return false;
}
- return nex;
+ return true;
}
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs b/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs
index 715207c2..5ec199d4 100644
--- a/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs
+++ b/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs
@@ -15,6 +15,21 @@ namespace BurnOutSharp.ExecutableType.Microsoft
///
public class PortableExecutable
{
+ ///
+ /// Value determining if the executable is initialized or not
+ ///
+ public bool Initialized { get; } = false;
+
+ ///
+ /// Source array that the executable was parsed from
+ ///
+ public byte[] SourceArray { get; } = null;
+
+ ///
+ /// Source stream that the executable was parsed from
+ ///
+ public Stream SourceStream { get; } = null;
+
#region Headers
///
@@ -25,7 +40,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft
/// At location 0x3c, the stub has the file offset to the PE signature.
/// This information enables Windows to properly execute the image file, even though it has an MS-DOS stub.
/// This file offset is placed at location 0x3c during linking.
- //
+ ///
public MSDOSExecutableHeader DOSStubHeader;
///
@@ -152,6 +167,220 @@ namespace BurnOutSharp.ExecutableType.Microsoft
#endregion
+ #region Constructors
+
+ ///
+ /// Create a PortableExecutable object from a stream
+ ///
+ /// Stream representing a file
+ ///
+ /// This constructor assumes that the stream is already in the correct position to start parsing
+ ///
+ public PortableExecutable(Stream stream)
+ {
+ if (stream == null || !stream.CanRead || !stream.CanSeek)
+ return;
+
+ this.Initialized = Deserialize(stream);
+ this.SourceStream = stream;
+ }
+
+ ///
+ /// Create a PortableExecutable object from a byte array
+ ///
+ /// Byte array representing a file
+ /// Positive offset representing the current position in the array
+ public PortableExecutable(byte[] fileContent, int offset)
+ {
+ if (fileContent == null || fileContent.Length == 0 || offset < 0)
+ return;
+
+ this.Initialized = Deserialize(fileContent, offset);
+ this.SourceArray = fileContent;
+ }
+
+ ///
+ /// Deserialize a PortableExecutable object from a stream
+ ///
+ /// Stream representing a file
+ private bool Deserialize(Stream stream)
+ {
+ try
+ {
+ // Attempt to read the DOS header first
+ this.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream); stream.Seek(this.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
+ if (this.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
+ return false;
+
+ // If the new header address is invalid for the file, it's not a PE
+ if (this.DOSStubHeader.NewExeHeaderAddr >= stream.Length)
+ return false;
+
+ // Then attempt to read the PE header
+ this.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(stream);
+ if (this.ImageFileHeader.Signature != Constants.IMAGE_NT_SIGNATURE)
+ return false;
+
+ // If the optional header is supposed to exist, read that as well
+ if (this.ImageFileHeader.SizeOfOptionalHeader > 0)
+ this.OptionalHeader = OptionalHeader.Deserialize(stream);
+
+ // Then read in the section table
+ this.SectionTable = new SectionHeader[this.ImageFileHeader.NumberOfSections];
+ for (int i = 0; i < this.ImageFileHeader.NumberOfSections; i++)
+ {
+ this.SectionTable[i] = SectionHeader.Deserialize(stream);
+ }
+
+ #region Structured Tables
+
+ // // Export Table
+ // var table = this.GetLastSection(".edata", true);
+ // if (table != null && table.VirtualSize > 0)
+ // {
+ // stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
+ // this.ExportTable = ExportDataSection.Deserialize(stream, this.SectionTable);
+ // }
+
+ // // Import Table
+ // table = this.GetSection(".idata", true);
+ // if (table != null && table.VirtualSize > 0)
+ // {
+ // stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
+ // this.ImportTable = ImportDataSection.Deserialize(stream, this.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
+ // }
+
+ // Resource Table
+ var table = this.GetLastSection(".rsrc", true);
+ if (table != null && table.VirtualSize > 0)
+ {
+ stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
+ this.ResourceSection = ResourceSection.Deserialize(stream, this.SectionTable);
+ }
+
+ #endregion
+
+ #region Freeform Sections
+
+ // Data Section
+ this.DataSectionRaw = this.ReadRawSection(stream, ".data", force: true, first: false) ?? this.ReadRawSection(stream, "DATA", force: true, first: false);
+
+ // Export Table
+ this.ExportDataSectionRaw = this.ReadRawSection(stream, ".edata", force: true, first: false);
+
+ // Import Table
+ this.ImportDataSectionRaw = this.ReadRawSection(stream, ".idata", force: true, first: false);
+
+ // Resource Data Section
+ this.ResourceDataSectionRaw = this.ReadRawSection(stream, ".rdata", force: true, first: false);
+
+ // Text Section
+ this.TextSectionRaw = this.ReadRawSection(stream, ".text", force: true, first: false);
+
+ #endregion
+ }
+ catch (Exception ex)
+ {
+ //Console.WriteLine($"Errored out on a file: {ex}");
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Deserialize a PortableExecutable object from a byte array
+ ///
+ /// Byte array representing a file
+ /// Positive offset representing the current position in the array
+ private bool Deserialize(byte[] content, int offset)
+ {
+ try
+ {
+ // Attempt to read the DOS header first
+ this.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, ref offset);
+ offset = this.DOSStubHeader.NewExeHeaderAddr;
+ if (this.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
+ return false;
+
+ // If the new header address is invalid for the file, it's not a PE
+ if (this.DOSStubHeader.NewExeHeaderAddr >= content.Length)
+ return false;
+
+ // Then attempt to read the PE header
+ this.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(content, ref offset);
+ if (this.ImageFileHeader.Signature != Constants.IMAGE_NT_SIGNATURE)
+ return false;
+
+ // If the optional header is supposed to exist, read that as well
+ if (this.ImageFileHeader.SizeOfOptionalHeader > 0)
+ this.OptionalHeader = OptionalHeader.Deserialize(content, ref offset);
+
+ // Then read in the section table
+ this.SectionTable = new SectionHeader[this.ImageFileHeader.NumberOfSections];
+ for (int i = 0; i < this.ImageFileHeader.NumberOfSections; i++)
+ {
+ this.SectionTable[i] = SectionHeader.Deserialize(content, ref offset);
+ }
+
+ #region Structured Tables
+
+ // // Export Table
+ // var table = this.GetLastSection(".edata", true);
+ // if (table != null && table.VirtualSize > 0)
+ // {
+ // int tableAddress = (int)table.PointerToRawData;
+ // this.ExportTable = ExportDataSection.Deserialize(content, ref tableAddress, this.SectionTable);
+ // }
+
+ // // Import Table
+ // table = this.GetSection(".idata", true);
+ // if (table != null && table.VirtualSize > 0)
+ // {
+ // int tableAddress = (int)table.PointerToRawData;
+ // this.ImportTable = ImportDataSection.Deserialize(content, tableAddress, this.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
+ // }
+
+ // Resource Table
+ var table = this.GetLastSection(".rsrc", true);
+ if (table != null && table.VirtualSize > 0)
+ {
+ int tableAddress = (int)table.PointerToRawData;
+ this.ResourceSection = ResourceSection.Deserialize(content, ref tableAddress, this.SectionTable);
+ }
+
+ #endregion
+
+ #region Freeform Sections
+
+ // Data Section
+ this.DataSectionRaw = this.ReadRawSection(content, ".data", force: true, first: false) ?? this.ReadRawSection(content, "DATA", force: true, first: false);
+
+ // Export Table
+ this.ExportDataSectionRaw = this.ReadRawSection(content, ".edata", force: true, first: false);
+
+ // Import Table
+ this.ImportDataSectionRaw = this.ReadRawSection(content, ".idata", force: true, first: false);
+
+ // Resource Data Section
+ this.ResourceDataSectionRaw = this.ReadRawSection(content, ".rdata", force: true, first: false);
+
+ // Text Section
+ this.TextSectionRaw = this.ReadRawSection(content, ".text", force: true, first: false);
+
+ #endregion
+ }
+ catch (Exception ex)
+ {
+ //Console.WriteLine($"Errored out on a file: {ex}");
+ return false;
+ }
+
+ return true;
+ }
+
+ #endregion
+
#region Helpers
///
@@ -356,180 +585,5 @@ namespace BurnOutSharp.ExecutableType.Microsoft
}
#endregion
-
- public static PortableExecutable Deserialize(Stream stream)
- {
- PortableExecutable pex = new PortableExecutable();
-
- try
- {
- // Attempt to read the DOS header first
- pex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(stream); stream.Seek(pex.DOSStubHeader.NewExeHeaderAddr, SeekOrigin.Begin);
- if (pex.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
- return null;
-
- // If the new header address is invalid for the file, it's not a PE
- if (pex.DOSStubHeader.NewExeHeaderAddr >= stream.Length)
- return null;
-
- // Then attempt to read the PE header
- pex.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(stream);
- if (pex.ImageFileHeader.Signature != Constants.IMAGE_NT_SIGNATURE)
- return null;
-
- // If the optional header is supposed to exist, read that as well
- if (pex.ImageFileHeader.SizeOfOptionalHeader > 0)
- pex.OptionalHeader = OptionalHeader.Deserialize(stream);
-
- // Then read in the section table
- pex.SectionTable = new SectionHeader[pex.ImageFileHeader.NumberOfSections];
- for (int i = 0; i < pex.ImageFileHeader.NumberOfSections; i++)
- {
- pex.SectionTable[i] = SectionHeader.Deserialize(stream);
- }
-
- #region Structured Tables
-
- // // Export Table
- // var table = pex.GetLastSection(".edata", true);
- // if (table != null && table.VirtualSize > 0)
- // {
- // stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
- // pex.ExportTable = ExportDataSection.Deserialize(stream, pex.SectionTable);
- // }
-
- // // Import Table
- // table = pex.GetSection(".idata", true);
- // if (table != null && table.VirtualSize > 0)
- // {
- // stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
- // pex.ImportTable = ImportDataSection.Deserialize(stream, pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
- // }
-
- // Resource Table
- var table = pex.GetLastSection(".rsrc", true);
- if (table != null && table.VirtualSize > 0)
- {
- stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin);
- pex.ResourceSection = ResourceSection.Deserialize(stream, pex.SectionTable);
- }
-
- #endregion
-
- #region Freeform Sections
-
- // Data Section
- pex.DataSectionRaw = pex.ReadRawSection(stream, ".data", force: true, first: false) ?? pex.ReadRawSection(stream, "DATA", force: true, first: false);
-
- // Export Table
- pex.ExportDataSectionRaw = pex.ReadRawSection(stream, ".edata", force: true, first: false);
-
- // Import Table
- pex.ImportDataSectionRaw = pex.ReadRawSection(stream, ".idata", force: true, first: false);
-
- // Resource Data Section
- pex.ResourceDataSectionRaw = pex.ReadRawSection(stream, ".rdata", force: true, first: false);
-
- // Text Section
- pex.TextSectionRaw = pex.ReadRawSection(stream, ".text", force: true, first: false);
-
- #endregion
- }
- catch (Exception ex)
- {
- //Console.WriteLine($"Errored out on a file: {ex}");
- return null;
- }
-
- return pex;
- }
-
- public static PortableExecutable Deserialize(byte[] content, int offset)
- {
- PortableExecutable pex = new PortableExecutable();
-
- try
- {
- // Attempt to read the DOS header first
- pex.DOSStubHeader = MSDOSExecutableHeader.Deserialize(content, ref offset);
- offset = pex.DOSStubHeader.NewExeHeaderAddr;
- if (pex.DOSStubHeader.Magic != Constants.IMAGE_DOS_SIGNATURE)
- return null;
-
- // If the new header address is invalid for the file, it's not a PE
- if (pex.DOSStubHeader.NewExeHeaderAddr >= content.Length)
- return null;
-
- // Then attempt to read the PE header
- pex.ImageFileHeader = CommonObjectFileFormatHeader.Deserialize(content, ref offset);
- if (pex.ImageFileHeader.Signature != Constants.IMAGE_NT_SIGNATURE)
- return null;
-
- // If the optional header is supposed to exist, read that as well
- if (pex.ImageFileHeader.SizeOfOptionalHeader > 0)
- pex.OptionalHeader = OptionalHeader.Deserialize(content, ref offset);
-
- // Then read in the section table
- pex.SectionTable = new SectionHeader[pex.ImageFileHeader.NumberOfSections];
- for (int i = 0; i < pex.ImageFileHeader.NumberOfSections; i++)
- {
- pex.SectionTable[i] = SectionHeader.Deserialize(content, ref offset);
- }
-
- #region Structured Tables
-
- // // Export Table
- // var table = pex.GetLastSection(".edata", true);
- // if (table != null && table.VirtualSize > 0)
- // {
- // int tableAddress = (int)table.PointerToRawData;
- // pex.ExportTable = ExportDataSection.Deserialize(content, ref tableAddress, pex.SectionTable);
- // }
-
- // // Import Table
- // table = pex.GetSection(".idata", true);
- // if (table != null && table.VirtualSize > 0)
- // {
- // int tableAddress = (int)table.PointerToRawData;
- // pex.ImportTable = ImportDataSection.Deserialize(content, tableAddress, pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0);
- // }
-
- // Resource Table
- var table = pex.GetLastSection(".rsrc", true);
- if (table != null && table.VirtualSize > 0)
- {
- int tableAddress = (int)table.PointerToRawData;
- pex.ResourceSection = ResourceSection.Deserialize(content, ref tableAddress, pex.SectionTable);
- }
-
- #endregion
-
- #region Freeform Sections
-
- // Data Section
- pex.DataSectionRaw = pex.ReadRawSection(content, ".data", force: true, first: false) ?? pex.ReadRawSection(content, "DATA", force: true, first: false);
-
- // Export Table
- pex.ExportDataSectionRaw = pex.ReadRawSection(content, ".edata", force: true, first: false);
-
- // Import Table
- pex.ImportDataSectionRaw = pex.ReadRawSection(content, ".idata", force: true, first: false);
-
- // Resource Data Section
- pex.ResourceDataSectionRaw = pex.ReadRawSection(content, ".rdata", force: true, first: false);
-
- // Text Section
- pex.TextSectionRaw = pex.ReadRawSection(content, ".text", force: true, first: false);
-
- #endregion
- }
- catch (Exception ex)
- {
- //Console.WriteLine($"Errored out on a file: {ex}");
- return null;
- }
-
- return pex;
- }
}
}
\ No newline at end of file
diff --git a/BurnOutSharp/FileType/Executable.cs b/BurnOutSharp/FileType/Executable.cs
index e1bd2b90..db292c7e 100644
--- a/BurnOutSharp/FileType/Executable.cs
+++ b/BurnOutSharp/FileType/Executable.cs
@@ -93,13 +93,13 @@ namespace BurnOutSharp.FileType
// Create PortableExecutable and NewExecutable objects for use in the checks
stream.Seek(0, SeekOrigin.Begin);
- PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
- NewExecutable nex = NewExecutable.Deserialize(fileContent, 0);
+ PortableExecutable pex = new PortableExecutable(fileContent, 0);
+ NewExecutable nex = new NewExecutable(fileContent, 0);
// Create PortableExecutable and NewExecutable objects for use in the checks
- // PortableExecutable pex = PortableExecutable.Deserialize(stream);
+ // PortableExecutable pex = new PortableExecutable(stream);
// stream.Seek(0, SeekOrigin.Begin);
- // NewExecutable nex = NewExecutable.Deserialize(stream);
+ // NewExecutable nex = new NewExecutable(stream);
// stream.Seek(0, SeekOrigin.Begin);
// Iterate through all content checks
diff --git a/BurnOutSharp/Tools/Utilities.cs b/BurnOutSharp/Tools/Utilities.cs
index 11088006..ede29346 100644
--- a/BurnOutSharp/Tools/Utilities.cs
+++ b/BurnOutSharp/Tools/Utilities.cs
@@ -207,7 +207,7 @@ namespace BurnOutSharp.Tools
if (fileContent == null || !fileContent.Any())
return null;
- return GetFileVersion(PortableExecutable.Deserialize(fileContent, 0));
+ return GetFileVersion(new PortableExecutable(fileContent, 0));
}
///