diff --git a/SabreTools.Serialization/Deserializers/PortableExecutable.cs b/SabreTools.Serialization/Deserializers/PortableExecutable.cs
index e5e0f5e0..bf2f02d2 100644
--- a/SabreTools.Serialization/Deserializers/PortableExecutable.cs
+++ b/SabreTools.Serialization/Deserializers/PortableExecutable.cs
@@ -20,7 +20,7 @@ namespace SabreTools.Serialization.Deserializers
try
{
// Cache the current offset
- int initialOffset = (int)data.Position;
+ long initialOffset = data.Position;
// Create a new executable to fill
var executable = new Executable();
@@ -49,23 +49,37 @@ namespace SabreTools.Serialization.Deserializers
#region COFF File Header
+ // Parse the COFF file header
+ var coffFileHeader = ParseCOFFFileHeader(data);
+ if (coffFileHeader == null)
+ return null;
+
// Set the COFF file header
- executable.COFFFileHeader = ParseCOFFFileHeader(data);
+ executable.COFFFileHeader = coffFileHeader;
#endregion
#region Optional Header
- // Set the optional header
- executable.OptionalHeader = ParseOptionalHeader(data, executable.COFFFileHeader.SizeOfOptionalHeader);
+ // If the optional header exists
+ OptionalHeader? optionalHeader = null;
+ if (coffFileHeader.SizeOfOptionalHeader > 0)
+ {
+ // Parse the optional header
+ optionalHeader = ParseOptionalHeader(data, coffFileHeader.SizeOfOptionalHeader);
+
+ // Set the optional header
+ if (optionalHeader != null)
+ executable.OptionalHeader = optionalHeader;
+ }
#endregion
#region Section Table
// Set the section table
- executable.SectionTable = new SectionHeader[executable.COFFFileHeader.NumberOfSections];
- for (int i = 0; i < executable.COFFFileHeader.NumberOfSections; i++)
+ executable.SectionTable = new SectionHeader[coffFileHeader.NumberOfSections];
+ for (int i = 0; i < coffFileHeader.NumberOfSections; i++)
{
executable.SectionTable[i] = ParseSectionHeader(data);
}
@@ -75,11 +89,11 @@ namespace SabreTools.Serialization.Deserializers
#region COFF Symbol Table and COFF String Table
// TODO: Validate that this is correct with an "old" PE
- if (executable.COFFFileHeader.PointerToSymbolTable.ConvertVirtualAddress(executable.SectionTable) != 0)
+ if (coffFileHeader.PointerToSymbolTable.ConvertVirtualAddress(executable.SectionTable) != 0)
{
// If the offset for the COFF symbol table doesn't exist
- int symbolTableAddress = initialOffset
- + (int)executable.COFFFileHeader.PointerToSymbolTable.ConvertVirtualAddress(executable.SectionTable);
+ long symbolTableAddress = initialOffset
+ + coffFileHeader.PointerToSymbolTable.ConvertVirtualAddress(executable.SectionTable);
if (symbolTableAddress >= data.Length)
return executable;
@@ -87,7 +101,7 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(symbolTableAddress, SeekOrigin.Begin);
// Set the COFF symbol table
- executable.COFFSymbolTable = ParseCOFFSymbolTable(data, executable.COFFFileHeader.NumberOfSymbols);
+ executable.COFFSymbolTable = ParseCOFFSymbolTable(data, coffFileHeader.NumberOfSymbols);
// Set the COFF string table
executable.COFFStringTable = ParseCOFFStringTable(data);
@@ -95,95 +109,14 @@ namespace SabreTools.Serialization.Deserializers
#endregion
- #region Attribute Certificate Table
-
- if (executable.OptionalHeader.CertificateTable != null && executable.OptionalHeader.CertificateTable.VirtualAddress != 0)
- {
- // If the offset for the attribute certificate table doesn't exist
- int certificateTableAddress = initialOffset
- + (int)executable.OptionalHeader.CertificateTable.VirtualAddress;
- if (certificateTableAddress >= data.Length)
- return executable;
-
- // Seek to the attribute certificate table
- data.Seek(certificateTableAddress, SeekOrigin.Begin);
- int endOffset = (int)(certificateTableAddress + executable.OptionalHeader.CertificateTable.Size);
-
- // Set the attribute certificate table
- executable.AttributeCertificateTable = ParseAttributeCertificateTable(data, endOffset);
- }
-
- #endregion
-
- #region Delay-Load Directory Table
-
- if (executable.OptionalHeader.DelayImportDescriptor != null && executable.OptionalHeader.DelayImportDescriptor.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
- {
- // If the offset for the delay-load directory table doesn't exist
- int delayLoadDirectoryTableAddress = initialOffset
- + (int)executable.OptionalHeader.DelayImportDescriptor.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
- if (delayLoadDirectoryTableAddress >= data.Length)
- return executable;
-
- // Seek to the delay-load directory table
- data.Seek(delayLoadDirectoryTableAddress, SeekOrigin.Begin);
-
- // Set the delay-load directory table
- executable.DelayLoadDirectoryTable = ParseDelayLoadDirectoryTable(data);
- }
-
- #endregion
-
- #region Base Relocation Table
-
- // Should also be in a '.reloc' section
- if (executable.OptionalHeader.BaseRelocationTable != null && executable.OptionalHeader.BaseRelocationTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
- {
- // If the offset for the base relocation table doesn't exist
- int baseRelocationTableAddress = initialOffset
- + (int)executable.OptionalHeader.BaseRelocationTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
- if (baseRelocationTableAddress >= data.Length)
- return executable;
-
- // Seek to the base relocation table
- data.Seek(baseRelocationTableAddress, SeekOrigin.Begin);
- int endOffset = (int)(baseRelocationTableAddress + executable.OptionalHeader.BaseRelocationTable.Size);
-
- // Set the base relocation table
- executable.BaseRelocationTable = ParseBaseRelocationTable(data, endOffset);
- }
-
- #endregion
-
- #region Debug Table
-
- // Should also be in a '.debug' section
- if (executable.OptionalHeader.Debug != null && executable.OptionalHeader.Debug.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
- {
- // If the offset for the debug table doesn't exist
- int debugTableAddress = initialOffset
- + (int)executable.OptionalHeader.Debug.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
- if (debugTableAddress >= data.Length)
- return executable;
-
- // Seek to the debug table
- data.Seek(debugTableAddress, SeekOrigin.Begin);
- int endOffset = (int)(debugTableAddress + executable.OptionalHeader.Debug.Size);
-
- // Set the debug table
- executable.DebugTable = ParseDebugTable(data, endOffset);
- }
-
- #endregion
-
#region Export Table
// Should also be in a '.edata' section
- if (executable.OptionalHeader.ExportTable != null && executable.OptionalHeader.ExportTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
+ if (optionalHeader?.ExportTable != null && optionalHeader.ExportTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
{
// If the offset for the export table doesn't exist
- int exportTableAddress = initialOffset
- + (int)executable.OptionalHeader.ExportTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
+ long exportTableAddress = initialOffset
+ + optionalHeader.ExportTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
if (exportTableAddress >= data.Length)
return executable;
@@ -199,11 +132,11 @@ namespace SabreTools.Serialization.Deserializers
#region Import Table
// Should also be in a '.idata' section
- if (executable.OptionalHeader.ImportTable != null && executable.OptionalHeader.ImportTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
+ if (optionalHeader?.ImportTable != null && optionalHeader.ImportTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
{
// If the offset for the import table doesn't exist
- int importTableAddress = initialOffset
- + (int)executable.OptionalHeader.ImportTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
+ long importTableAddress = initialOffset
+ + optionalHeader.ImportTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
if (importTableAddress >= data.Length)
return executable;
@@ -211,7 +144,7 @@ namespace SabreTools.Serialization.Deserializers
data.Seek(importTableAddress, SeekOrigin.Begin);
// Set the import table
- executable.ImportTable = ParseImportTable(data, executable.OptionalHeader.Magic, executable.SectionTable);
+ executable.ImportTable = ParseImportTable(data, optionalHeader.Magic, executable.SectionTable);
}
#endregion
@@ -219,11 +152,11 @@ namespace SabreTools.Serialization.Deserializers
#region Resource Directory Table
// Should also be in a '.rsrc' section
- if (executable.OptionalHeader.ResourceTable != null && executable.OptionalHeader.ResourceTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
+ if (optionalHeader?.ResourceTable != null && optionalHeader.ResourceTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
{
// If the offset for the resource directory table doesn't exist
- int resourceTableAddress = initialOffset
- + (int)executable.OptionalHeader.ResourceTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
+ long resourceTableAddress = initialOffset
+ + optionalHeader.ResourceTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
if (resourceTableAddress >= data.Length)
return executable;
@@ -236,7 +169,99 @@ namespace SabreTools.Serialization.Deserializers
#endregion
- // TODO: Finish implementing PE parsing
+ // TODO: Exception Table
+
+ #region Certificate Table
+
+ if (optionalHeader?.CertificateTable != null && optionalHeader.CertificateTable.VirtualAddress != 0)
+ {
+ // If the offset for the attribute certificate table doesn't exist
+ long certificateTableAddress = initialOffset
+ + optionalHeader.CertificateTable.VirtualAddress;
+ if (certificateTableAddress >= data.Length)
+ return executable;
+
+ // Seek to the attribute certificate table
+ data.Seek(certificateTableAddress, SeekOrigin.Begin);
+ long endOffset = certificateTableAddress + optionalHeader.CertificateTable.Size;
+
+ // Set the attribute certificate table
+ executable.AttributeCertificateTable = ParseAttributeCertificateTable(data, endOffset);
+ }
+
+ #endregion
+
+ #region Base Relocation Table
+
+ // Should also be in a '.reloc' section
+ if (optionalHeader?.BaseRelocationTable != null && optionalHeader.BaseRelocationTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
+ {
+ // If the offset for the base relocation table doesn't exist
+ long baseRelocationTableAddress = initialOffset
+ + optionalHeader.BaseRelocationTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
+ if (baseRelocationTableAddress >= data.Length)
+ return executable;
+
+ // Seek to the base relocation table
+ data.Seek(baseRelocationTableAddress, SeekOrigin.Begin);
+ long endOffset = baseRelocationTableAddress + optionalHeader.BaseRelocationTable.Size;
+
+ // Set the base relocation table
+ executable.BaseRelocationTable = ParseBaseRelocationTable(data, endOffset);
+ }
+
+ #endregion
+
+ #region Debug Table
+
+ // Should also be in a '.debug' section
+ if (optionalHeader?.Debug != null && optionalHeader.Debug.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
+ {
+ // If the offset for the debug table doesn't exist
+ long debugTableAddress = initialOffset
+ + optionalHeader.Debug.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
+ if (debugTableAddress >= data.Length)
+ return executable;
+
+ // Seek to the debug table
+ data.Seek(debugTableAddress, SeekOrigin.Begin);
+ long endOffset = debugTableAddress + optionalHeader.Debug.Size;
+
+ // Set the debug table
+ executable.DebugTable = ParseDebugTable(data, endOffset);
+ }
+
+ #endregion
+
+ // TODO: Architecture Table
+ // TODO: Global Pointer Register
+ // TODO: Thread Local Storage (TLS) Table (.tls section)
+ // TODO: Load Config Table
+ // TODO: Bound Import Table
+ // TODO: Import Address Table
+
+ #region Delay-Load Directory Table
+
+ if (optionalHeader?.DelayImportDescriptor != null && optionalHeader.DelayImportDescriptor.VirtualAddress.ConvertVirtualAddress(executable.SectionTable) != 0)
+ {
+ // If the offset for the delay-load directory table doesn't exist
+ long delayLoadDirectoryTableAddress = initialOffset
+ + optionalHeader.DelayImportDescriptor.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
+ if (delayLoadDirectoryTableAddress >= data.Length)
+ return executable;
+
+ // Seek to the delay-load directory table
+ data.Seek(delayLoadDirectoryTableAddress, SeekOrigin.Begin);
+
+ // Set the delay-load directory table
+ executable.DelayLoadDirectoryTable = ParseDelayLoadDirectoryTable(data);
+ }
+
+ #endregion
+
+ // TODO: CLR Runtime Header
+ // TODO: Reserved
+
return executable;
}
catch
@@ -252,7 +277,7 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// First address not part of the attribute certificate table
/// Filled attribute certificate on success, null on error
- public static AttributeCertificateTableEntry[] ParseAttributeCertificateTable(Stream data, int endOffset)
+ public static AttributeCertificateTableEntry[] ParseAttributeCertificateTable(Stream data, long endOffset)
{
var attributeCertificateTable = new List();
@@ -294,7 +319,7 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// First address not part of the base relocation table
/// Filled base relocation table on success, null on error
- public static BaseRelocationBlock[] ParseBaseRelocationTable(Stream data, int endOffset)
+ public static BaseRelocationBlock[] ParseBaseRelocationTable(Stream data, long endOffset)
{
var baseRelocationTable = new List();
@@ -580,7 +605,7 @@ namespace SabreTools.Serialization.Deserializers
/// Stream to parse
/// First address not part of the debug table
/// Filled DebugTable on success, null on error
- public static DebugTable ParseDebugTable(Stream data, int endOffset)
+ public static DebugTable ParseDebugTable(Stream data, long endOffset)
{
var debugTable = new DebugTable();