mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-04-20 05:03:11 +00:00
Migrate remaining models from Models
This commit is contained in:
@@ -28,7 +28,6 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="1.5.0" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.7.2" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -2,8 +2,8 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.LinearExecutable;
|
||||
using static SabreTools.Models.LinearExecutable.Constants;
|
||||
using SabreTools.Serialization.Models.LinearExecutable;
|
||||
using static SabreTools.Serialization.Models.LinearExecutable.Constants;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.MSDOS;
|
||||
using static SabreTools.Models.MSDOS.Constants;
|
||||
using SabreTools.Serialization.Models.MSDOS;
|
||||
using static SabreTools.Serialization.Models.MSDOS.Constants;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
|
||||
@@ -2,9 +2,9 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.NewExecutable;
|
||||
using SabreTools.Serialization.Extensions;
|
||||
using static SabreTools.Models.NewExecutable.Constants;
|
||||
using SabreTools.Serialization.Models.NewExecutable;
|
||||
using static SabreTools.Serialization.Models.NewExecutable.Constants;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
@@ -253,7 +253,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
obj.MovableEntriesCount = data.ReadUInt16LittleEndian();
|
||||
obj.SegmentAlignmentShiftCount = data.ReadUInt16LittleEndian();
|
||||
obj.ResourceEntriesCount = data.ReadUInt16LittleEndian();
|
||||
obj.TargetOperatingSystem = (SabreTools.Models.NewExecutable.OperatingSystem)data.ReadByteValue();
|
||||
obj.TargetOperatingSystem = (SabreTools.Serialization.Models.NewExecutable.OperatingSystem)data.ReadByteValue();
|
||||
obj.AdditionalFlags = (OS2Flag)data.ReadByteValue();
|
||||
obj.ReturnThunkOffset = data.ReadUInt16LittleEndian();
|
||||
obj.SegmentReferenceThunkOffset = data.ReadUInt16LittleEndian();
|
||||
|
||||
@@ -3,12 +3,12 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.COFF;
|
||||
using SabreTools.Models.COFF.SymbolTableEntries;
|
||||
using SabreTools.Models.PortableExecutable;
|
||||
using SabreTools.Serialization.Extensions;
|
||||
using static SabreTools.Models.COFF.Constants;
|
||||
using static SabreTools.Models.PortableExecutable.Constants;
|
||||
using SabreTools.Serialization.Models.COFF;
|
||||
using SabreTools.Serialization.Models.COFF.SymbolTableEntries;
|
||||
using SabreTools.Serialization.Models.PortableExecutable;
|
||||
using static SabreTools.Serialization.Models.COFF.Constants;
|
||||
using static SabreTools.Serialization.Models.PortableExecutable.Constants;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
@@ -74,7 +74,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
#region Optional Header
|
||||
|
||||
// If the optional header exists
|
||||
SabreTools.Models.PortableExecutable.OptionalHeader? optionalHeader = null;
|
||||
SabreTools.Serialization.Models.PortableExecutable.OptionalHeader? optionalHeader = null;
|
||||
if (fileHeader.SizeOfOptionalHeader > 0)
|
||||
{
|
||||
// Parse the optional header
|
||||
@@ -337,12 +337,12 @@ namespace SabreTools.Serialization.Deserializers
|
||||
int length = tableSize - tableOffset;
|
||||
|
||||
// Add the hidden entry
|
||||
pex.ResourceDirectoryTable.Entries[localEntries.Length - 1] = new SabreTools.Models.PortableExecutable.Resource.DirectoryEntry
|
||||
pex.ResourceDirectoryTable.Entries[localEntries.Length - 1] = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryEntry
|
||||
{
|
||||
Name = new SabreTools.Models.PortableExecutable.Resource.DirectoryString { UnicodeString = Encoding.Unicode.GetBytes("HIDDEN RESOURCE") },
|
||||
Name = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryString { UnicodeString = Encoding.Unicode.GetBytes("HIDDEN RESOURCE") },
|
||||
IntegerID = uint.MaxValue,
|
||||
DataEntryOffset = (uint)tableOffset,
|
||||
DataEntry = new SabreTools.Models.PortableExecutable.Resource.DataEntry
|
||||
DataEntry = new SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry
|
||||
{
|
||||
Size = (uint)length,
|
||||
Data = tableData.ReadBytes(ref tableOffset, length),
|
||||
@@ -471,12 +471,12 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <returns>Filled attribute certificate on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.AttributeCertificate.Entry[]? ParseAttributeCertificateTable(byte[]? data)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.AttributeCertificate.Entry[]? ParseAttributeCertificateTable(byte[]? data)
|
||||
{
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
var obj = new List<SabreTools.Models.PortableExecutable.AttributeCertificate.Entry>();
|
||||
var obj = new List<SabreTools.Serialization.Models.PortableExecutable.AttributeCertificate.Entry>();
|
||||
|
||||
int offset = 0;
|
||||
while (offset < data.Length)
|
||||
@@ -502,9 +502,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <returns>Filled AttributeCertificateTableEntry on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.AttributeCertificate.Entry? ParseAttributeCertificateTableEntry(byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.AttributeCertificate.Entry? ParseAttributeCertificateTableEntry(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.AttributeCertificate.Entry();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.AttributeCertificate.Entry();
|
||||
|
||||
obj.Length = data.ReadUInt32LittleEndian(ref offset);
|
||||
if (obj.Length < 8)
|
||||
@@ -526,9 +526,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled BaseRelocationBlock on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.BaseRelocation.Block? ParseBaseRelocationBlock(byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.Block? ParseBaseRelocationBlock(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.BaseRelocation.Block();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.Block();
|
||||
|
||||
obj.PageRVA = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.BlockSize = data.ReadUInt32LittleEndian(ref offset);
|
||||
@@ -542,7 +542,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
return obj;
|
||||
|
||||
int entryCount = ((int)obj.BlockSize - 8) / 2;
|
||||
obj.TypeOffsetFieldEntries = new SabreTools.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry[entryCount];
|
||||
obj.TypeOffsetFieldEntries = new SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry[entryCount];
|
||||
for (int i = 0; i < obj.TypeOffsetFieldEntries.Length; i++)
|
||||
{
|
||||
if (offset + 2 >= data.Length)
|
||||
@@ -559,12 +559,12 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <returns>Filled base relocation table on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.BaseRelocation.Block[]? ParseBaseRelocationTable(byte[]? data)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.Block[]? ParseBaseRelocationTable(byte[]? data)
|
||||
{
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
var obj = new List<SabreTools.Models.PortableExecutable.BaseRelocation.Block>();
|
||||
var obj = new List<SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.Block>();
|
||||
|
||||
int offset = 0;
|
||||
while (offset + 8 <= data.Length)
|
||||
@@ -591,9 +591,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled BaseRelocationTypeOffsetFieldEntry on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry ParseBaseRelocationTypeOffsetFieldEntry(byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry ParseBaseRelocationTypeOffsetFieldEntry(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.BaseRelocation.TypeOffsetFieldEntry();
|
||||
|
||||
ushort typeAndOffsetField = data.ReadUInt16LittleEndian(ref offset);
|
||||
obj.BaseRelocationType = (BaseRelocationTypes)(typeAndOffsetField >> 12);
|
||||
@@ -640,9 +640,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled DebugDirectoryEntry on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.DebugData.Entry ParseDebugDirectoryEntry(byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.DebugData.Entry ParseDebugDirectoryEntry(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.DebugData.Entry();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.DebugData.Entry();
|
||||
|
||||
obj.Characteristics = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.TimeDateStamp = data.ReadUInt32LittleEndian(ref offset);
|
||||
@@ -661,14 +661,14 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <returns>Filled DebugTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.DebugData.Table? ParseDebugTable(byte[]? data)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.DebugData.Table? ParseDebugTable(byte[]? data)
|
||||
{
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
var obj = new SabreTools.Models.PortableExecutable.DebugData.Table();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.DebugData.Table();
|
||||
|
||||
var table = new List<SabreTools.Models.PortableExecutable.DebugData.Entry>();
|
||||
var table = new List<SabreTools.Serialization.Models.PortableExecutable.DebugData.Entry>();
|
||||
|
||||
int offset = 0;
|
||||
while (offset < data.Length)
|
||||
@@ -693,12 +693,12 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <returns>Filled DelayLoadDirectoryTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.DelayLoad.DirectoryTable? ParseDelayLoadDirectoryTable(byte[]? data)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.DelayLoad.DirectoryTable? ParseDelayLoadDirectoryTable(byte[]? data)
|
||||
{
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
var obj = new SabreTools.Models.PortableExecutable.DelayLoad.DirectoryTable();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.DelayLoad.DirectoryTable();
|
||||
|
||||
int offset = 0;
|
||||
obj.Attributes = data.ReadUInt32LittleEndian(ref offset);
|
||||
@@ -737,9 +737,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="entries">Number of entries in the table</param>
|
||||
/// <returns>Filled ExportAddressTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Export.AddressTableEntry[] ParseExportAddressTable(Stream data, uint entries)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Export.AddressTableEntry[] ParseExportAddressTable(Stream data, uint entries)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Export.AddressTableEntry[entries];
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.AddressTableEntry[entries];
|
||||
|
||||
for (int i = 0; i < obj.Length; i++)
|
||||
{
|
||||
@@ -754,9 +754,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled ExportAddressTableEntry on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Export.AddressTableEntry ParseExportAddressTableEntry(Stream data)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Export.AddressTableEntry ParseExportAddressTableEntry(Stream data)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Export.AddressTableEntry();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.AddressTableEntry();
|
||||
|
||||
obj.ExportRVA = data.ReadUInt32LittleEndian();
|
||||
obj.ForwarderRVA = obj.ExportRVA;
|
||||
@@ -770,9 +770,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled ExportDirectoryTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Export.DirectoryTable ParseExportDirectoryTable(byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Export.DirectoryTable ParseExportDirectoryTable(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Export.DirectoryTable();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.DirectoryTable();
|
||||
|
||||
obj.ExportFlags = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.TimeDateStamp = data.ReadUInt32LittleEndian(ref offset);
|
||||
@@ -797,9 +797,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="pointers">Set of pointers to process</param>
|
||||
/// <param name="sections">Section table to use for virtual address translation</param>
|
||||
/// <returns>Filled ExportNameTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Export.NameTable ParseExportNameTable(Stream data, long initialOffset, uint[] pointers, SectionHeader[] sections)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Export.NameTable ParseExportNameTable(Stream data, long initialOffset, uint[] pointers, SectionHeader[] sections)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Export.NameTable();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.NameTable();
|
||||
|
||||
obj.Strings = new string[pointers.Length];
|
||||
for (int i = 0; i < obj.Strings.Length; i++)
|
||||
@@ -827,9 +827,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="entries">Number of entries in the table</param>
|
||||
/// <returns>Filled ExportNamePointerTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Export.NamePointerTable ParseExportNamePointerTable(Stream data, uint entries)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Export.NamePointerTable ParseExportNamePointerTable(Stream data, uint entries)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Export.NamePointerTable();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.NamePointerTable();
|
||||
|
||||
obj.Pointers = new uint[entries];
|
||||
for (int i = 0; i < obj.Pointers.Length; i++)
|
||||
@@ -846,9 +846,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="entries">Number of entries in the table</param>
|
||||
/// <returns>Filled ExportOrdinalTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Export.OrdinalTable ParseExportOrdinalTable(Stream data, uint entries)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Export.OrdinalTable ParseExportOrdinalTable(Stream data, uint entries)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Export.OrdinalTable();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Export.OrdinalTable();
|
||||
|
||||
obj.Indexes = new ushort[entries];
|
||||
for (int i = 0; i < obj.Indexes.Length; i++)
|
||||
@@ -921,13 +921,13 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="importAddressTables">Import address tables</param>
|
||||
/// <param name="sections">Section table to use for virtual address translation</param>
|
||||
/// <returns>Filled HintNameTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Import.HintNameTableEntry[] ParseHintNameTable(Stream data,
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Import.HintNameTableEntry[] ParseHintNameTable(Stream data,
|
||||
long initialOffset,
|
||||
Dictionary<int, SabreTools.Models.PortableExecutable.Import.LookupTableEntry[]?> importLookupTables,
|
||||
Dictionary<int, SabreTools.Models.PortableExecutable.Import.AddressTableEntry[]?> importAddressTables,
|
||||
Dictionary<int, SabreTools.Serialization.Models.PortableExecutable.Import.LookupTableEntry[]?> importLookupTables,
|
||||
Dictionary<int, SabreTools.Serialization.Models.PortableExecutable.Import.AddressTableEntry[]?> importAddressTables,
|
||||
SectionHeader[] sections)
|
||||
{
|
||||
var importHintNameTable = new List<SabreTools.Models.PortableExecutable.Import.HintNameTableEntry>();
|
||||
var importHintNameTable = new List<SabreTools.Serialization.Models.PortableExecutable.Import.HintNameTableEntry>();
|
||||
|
||||
if (importLookupTables.Count > 0 || importAddressTables.Count > 0)
|
||||
{
|
||||
@@ -1005,9 +1005,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled HintNameTableEntry on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Import.HintNameTableEntry ParseHintNameTableEntry(Stream data)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Import.HintNameTableEntry ParseHintNameTableEntry(Stream data)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Import.HintNameTableEntry();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Import.HintNameTableEntry();
|
||||
|
||||
obj.Hint = data.ReadUInt16LittleEndian();
|
||||
obj.Name = data.ReadNullTerminatedAnsiString();
|
||||
@@ -1021,9 +1021,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="magic">Optional header magic number indicating PE32 or PE32+</param>
|
||||
/// <returns>Filled ImportAddressTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Import.AddressTableEntry[] ParseImportAddressTable(Stream data, OptionalHeaderMagicNumber magic)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Import.AddressTableEntry[] ParseImportAddressTable(Stream data, OptionalHeaderMagicNumber magic)
|
||||
{
|
||||
var obj = new List<SabreTools.Models.PortableExecutable.Import.AddressTableEntry>();
|
||||
var obj = new List<SabreTools.Serialization.Models.PortableExecutable.Import.AddressTableEntry>();
|
||||
|
||||
// Loop until the last item (all nulls) are found
|
||||
while (data.Position < data.Length)
|
||||
@@ -1050,13 +1050,13 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="entries">Directory table entries containing the addresses</param>
|
||||
/// <param name="sections">Section table to use for virtual address translation</param>
|
||||
/// <returns>Filled ImportAddressTables on success, null on error</returns>
|
||||
public static Dictionary<int, SabreTools.Models.PortableExecutable.Import.AddressTableEntry[]?> ParseImportAddressTables(Stream data,
|
||||
public static Dictionary<int, SabreTools.Serialization.Models.PortableExecutable.Import.AddressTableEntry[]?> ParseImportAddressTables(Stream data,
|
||||
long initialOffset,
|
||||
OptionalHeaderMagicNumber magic,
|
||||
SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry[] entries,
|
||||
SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry[] entries,
|
||||
SectionHeader[] sections)
|
||||
{
|
||||
var obj = new Dictionary<int, SabreTools.Models.PortableExecutable.Import.AddressTableEntry[]?>();
|
||||
var obj = new Dictionary<int, SabreTools.Serialization.Models.PortableExecutable.Import.AddressTableEntry[]?>();
|
||||
|
||||
for (int i = 0; i < entries.Length; i++)
|
||||
{
|
||||
@@ -1083,9 +1083,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="magic">Optional header magic number</param>
|
||||
/// <returns>Filled ImportAddressTableEntry on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Import.AddressTableEntry ParseImportAddressTableEntry(Stream data, OptionalHeaderMagicNumber magic)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Import.AddressTableEntry ParseImportAddressTableEntry(Stream data, OptionalHeaderMagicNumber magic)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Import.AddressTableEntry();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Import.AddressTableEntry();
|
||||
|
||||
if (magic == OptionalHeaderMagicNumber.PE32)
|
||||
{
|
||||
@@ -1115,9 +1115,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled ImportDirectoryTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry[] ParseImportDirectoryTable(byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry[] ParseImportDirectoryTable(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new List<SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry>();
|
||||
var obj = new List<SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry>();
|
||||
|
||||
// Loop until the last item (all nulls) are found
|
||||
while (offset < data.Length)
|
||||
@@ -1143,9 +1143,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled ImportDirectoryTableEntry on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry ParseImportDirectoryTableEntry(byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry ParseImportDirectoryTableEntry(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry();
|
||||
|
||||
obj.ImportLookupTableRVA = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.TimeDateStamp = data.ReadUInt32LittleEndian(ref offset);
|
||||
@@ -1162,9 +1162,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="magic">Optional header magic number indicating PE32 or PE32+</param>
|
||||
/// <returns>Filled ImportLookupTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Import.LookupTableEntry[] ParseImportLookupTable(Stream data, OptionalHeaderMagicNumber magic)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Import.LookupTableEntry[] ParseImportLookupTable(Stream data, OptionalHeaderMagicNumber magic)
|
||||
{
|
||||
var obj = new List<SabreTools.Models.PortableExecutable.Import.LookupTableEntry>();
|
||||
var obj = new List<SabreTools.Serialization.Models.PortableExecutable.Import.LookupTableEntry>();
|
||||
|
||||
// Loop until the last item (all nulls) are found
|
||||
while (data.Position < data.Length)
|
||||
@@ -1191,14 +1191,14 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="entries">Directory table entries containing the addresses</param>
|
||||
/// <param name="sections">Section table to use for virtual address translation</param>
|
||||
/// <returns>Filled ImportLookupTables on success, null on error</returns>
|
||||
public static Dictionary<int, SabreTools.Models.PortableExecutable.Import.LookupTableEntry[]?> ParseImportLookupTables(Stream data,
|
||||
public static Dictionary<int, SabreTools.Serialization.Models.PortableExecutable.Import.LookupTableEntry[]?> ParseImportLookupTables(Stream data,
|
||||
long initialOffset,
|
||||
OptionalHeaderMagicNumber magic,
|
||||
SabreTools.Models.PortableExecutable.Import.DirectoryTableEntry[] entries,
|
||||
SabreTools.Serialization.Models.PortableExecutable.Import.DirectoryTableEntry[] entries,
|
||||
SectionHeader[] sections)
|
||||
{
|
||||
// Lookup tables
|
||||
var obj = new Dictionary<int, SabreTools.Models.PortableExecutable.Import.LookupTableEntry[]?>();
|
||||
var obj = new Dictionary<int, SabreTools.Serialization.Models.PortableExecutable.Import.LookupTableEntry[]?>();
|
||||
|
||||
for (int i = 0; i < entries.Length; i++)
|
||||
{
|
||||
@@ -1225,9 +1225,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="magic">Optional header magic number</param>
|
||||
/// <returns>Filled ImportLookupTableEntry on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Import.LookupTableEntry ParseImportLookupTableEntry(Stream data, OptionalHeaderMagicNumber magic)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Import.LookupTableEntry ParseImportLookupTableEntry(Stream data, OptionalHeaderMagicNumber magic)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Import.LookupTableEntry();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Import.LookupTableEntry();
|
||||
|
||||
if (magic == OptionalHeaderMagicNumber.PE32)
|
||||
{
|
||||
@@ -1275,11 +1275,11 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="optionalSize">Size of the optional header</param>
|
||||
/// <returns>Filled OptionalHeader on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.OptionalHeader ParseOptionalHeader(Stream data, int optionalSize)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.OptionalHeader ParseOptionalHeader(Stream data, int optionalSize)
|
||||
{
|
||||
long initialOffset = data.Position;
|
||||
|
||||
var obj = new SabreTools.Models.PortableExecutable.OptionalHeader();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.OptionalHeader();
|
||||
|
||||
#region Standard Fields
|
||||
|
||||
@@ -1431,7 +1431,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
ref int dataOffset,
|
||||
long tableStart,
|
||||
long tableLength,
|
||||
SabreTools.Models.PortableExecutable.Resource.DirectoryTable? table,
|
||||
SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryTable? table,
|
||||
SectionHeader[] sections)
|
||||
{
|
||||
if (tableData == null)
|
||||
@@ -1484,9 +1484,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled ResourceDataEntry on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Resource.DataEntry ParseResourceDataEntry(byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry ParseResourceDataEntry(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Resource.DataEntry();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry();
|
||||
|
||||
obj.DataRVA = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.Size = data.ReadUInt32LittleEndian(ref offset);
|
||||
@@ -1503,9 +1503,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <param name="nameEntry">Indicates if the value is a name entry or not</param>
|
||||
/// <returns>Filled ResourceDirectoryEntry on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Resource.DirectoryEntry ParseResourceDirectoryEntry(byte[] data, ref int offset, bool nameEntry)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryEntry ParseResourceDirectoryEntry(byte[] data, ref int offset, bool nameEntry)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Resource.DirectoryEntry();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryEntry();
|
||||
|
||||
// TODO: Figure out why the high bit is set for names
|
||||
// The original version of this code also had this fix, but there
|
||||
@@ -1532,9 +1532,9 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled ResourceDirectoryString on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Resource.DirectoryString ParseResourceDirectoryString(byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryString ParseResourceDirectoryString(byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.Resource.DirectoryString();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryString();
|
||||
|
||||
obj.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
if (obj.Length > 0 && offset + (obj.Length * 2) <= data.Length)
|
||||
@@ -1549,12 +1549,12 @@ namespace SabreTools.Serialization.Deserializers
|
||||
/// <param name="tableData">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>Filled ResourceDirectoryTable on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Resource.DirectoryTable? ParseResourceDirectoryTable(byte[]? tableData, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryTable? ParseResourceDirectoryTable(byte[]? tableData, ref int offset)
|
||||
{
|
||||
if (tableData == null)
|
||||
return null;
|
||||
|
||||
var obj = new SabreTools.Models.PortableExecutable.Resource.DirectoryTable();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryTable();
|
||||
|
||||
obj.Characteristics = tableData.ReadUInt32LittleEndian(ref offset);
|
||||
if (obj.Characteristics != 0)
|
||||
@@ -1568,7 +1568,7 @@ namespace SabreTools.Serialization.Deserializers
|
||||
|
||||
// Create the entry array
|
||||
int totalEntryCount = obj.NumberOfNameEntries + obj.NumberOfIDEntries;
|
||||
obj.Entries = new SabreTools.Models.PortableExecutable.Resource.DirectoryEntry[totalEntryCount];
|
||||
obj.Entries = new SabreTools.Serialization.Models.PortableExecutable.Resource.DirectoryEntry[totalEntryCount];
|
||||
if (obj.Entries.Length == 0)
|
||||
return obj;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.SecuROM;
|
||||
using SabreTools.Serialization.Models.SecuROM;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.SecuROM;
|
||||
using static SabreTools.Models.SecuROM.Constants;
|
||||
using SabreTools.Serialization.Models.SecuROM;
|
||||
using static SabreTools.Serialization.Models.SecuROM.Constants;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.SecuROM;
|
||||
using static SabreTools.Models.SecuROM.Constants;
|
||||
using SabreTools.Serialization.Models.SecuROM;
|
||||
using static SabreTools.Serialization.Models.SecuROM.Constants;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.WiseInstaller;
|
||||
using SabreTools.Serialization.Models.WiseInstaller;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.WiseInstaller;
|
||||
using SabreTools.Models.WiseInstaller.Actions;
|
||||
using SabreTools.Serialization.Models.WiseInstaller;
|
||||
using SabreTools.Serialization.Models.WiseInstaller.Actions;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.WiseInstaller;
|
||||
using static SabreTools.Models.WiseInstaller.Constants;
|
||||
using SabreTools.Serialization.Models.WiseInstaller;
|
||||
using static SabreTools.Serialization.Models.WiseInstaller.Constants;
|
||||
|
||||
namespace SabreTools.Serialization.Deserializers
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using SabreTools.Models.NewExecutable;
|
||||
using SabreTools.Serialization.Models.NewExecutable;
|
||||
|
||||
namespace SabreTools.Serialization.Extensions
|
||||
{
|
||||
|
||||
@@ -4,10 +4,10 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.COFF;
|
||||
using SabreTools.Models.PortableExecutable;
|
||||
using SabreTools.Models.PortableExecutable.Resource.Entries;
|
||||
using SabreTools.Models.SecuROM;
|
||||
using SabreTools.Serialization.Models.COFF;
|
||||
using SabreTools.Serialization.Models.PortableExecutable;
|
||||
using SabreTools.Serialization.Models.PortableExecutable.Resource.Entries;
|
||||
using SabreTools.Serialization.Models.SecuROM;
|
||||
|
||||
namespace SabreTools.Serialization.Extensions
|
||||
{
|
||||
@@ -110,9 +110,9 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled NB10ProgramDatabase on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.DebugData.NB10ProgramDatabase? ParseNB10ProgramDatabase(this byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.DebugData.NB10ProgramDatabase? ParseNB10ProgramDatabase(this byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.DebugData.NB10ProgramDatabase();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.DebugData.NB10ProgramDatabase();
|
||||
|
||||
obj.Signature = data.ReadUInt32LittleEndian(ref offset);
|
||||
if (obj.Signature != 0x3031424E)
|
||||
@@ -132,9 +132,9 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled RSDSProgramDatabase on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.DebugData.RSDSProgramDatabase? ParseRSDSProgramDatabase(this byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.DebugData.RSDSProgramDatabase? ParseRSDSProgramDatabase(this byte[] data, ref int offset)
|
||||
{
|
||||
var obj = new SabreTools.Models.PortableExecutable.DebugData.RSDSProgramDatabase();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.DebugData.RSDSProgramDatabase();
|
||||
|
||||
obj.Signature = data.ReadUInt32LittleEndian(ref offset);
|
||||
if (obj.Signature != 0x53445352)
|
||||
@@ -231,7 +231,7 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// </summary>
|
||||
/// <param name="entry">Resource data entry to parse into an accelerator table resource</param>
|
||||
/// <returns>A filled accelerator table resource on success, null on error</returns>
|
||||
public static AcceleratorTableEntry[]? AsAcceleratorTableResource(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
public static AcceleratorTableEntry[]? AsAcceleratorTableResource(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
{
|
||||
// If we have data that's invalid for this resource type, we can't do anything
|
||||
if (entry?.Data == null || entry.Data.Length % 8 != 0)
|
||||
@@ -260,7 +260,7 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// </summary>
|
||||
/// <param name="entry">Resource data entry to parse into a side-by-side assembly manifest</param>
|
||||
/// <returns>A filled side-by-side assembly manifest on success, null on error</returns>
|
||||
public static AssemblyManifest? AsAssemblyManifest(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
public static AssemblyManifest? AsAssemblyManifest(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
{
|
||||
// If we have an invalid entry, just skip
|
||||
if (entry?.Data == null)
|
||||
@@ -282,7 +282,7 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// </summary>
|
||||
/// <param name="entry">Resource data entry to parse into a dialog box</param>
|
||||
/// <returns>A filled dialog box on success, null on error</returns>
|
||||
public static DialogBoxResource? AsDialogBox(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
public static DialogBoxResource? AsDialogBox(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
{
|
||||
// If we have an invalid entry, just skip
|
||||
if (entry?.Data == null)
|
||||
@@ -759,7 +759,7 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// </summary>
|
||||
/// <param name="entry">Resource data entry to parse into a font group</param>
|
||||
/// <returns>A filled font group on success, null on error</returns>
|
||||
public static FontGroupHeader? AsFontGroup(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
public static FontGroupHeader? AsFontGroup(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
{
|
||||
// If we have an invalid entry, just skip
|
||||
if (entry?.Data == null)
|
||||
@@ -828,7 +828,7 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// </summary>
|
||||
/// <param name="entry">Resource data entry to parse into a menu</param>
|
||||
/// <returns>A filled menu on success, null on error</returns>
|
||||
public static MenuResource? AsMenu(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
public static MenuResource? AsMenu(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
{
|
||||
// If we have an invalid entry, just skip
|
||||
if (entry?.Data == null)
|
||||
@@ -924,7 +924,7 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// </summary>
|
||||
/// <param name="entry">Resource data entry to parse into a message table resource</param>
|
||||
/// <returns>A filled message table resource on success, null on error</returns>
|
||||
public static MessageResourceData? AsMessageResourceData(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
public static MessageResourceData? AsMessageResourceData(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
{
|
||||
// If we have an invalid entry, just skip
|
||||
if (entry?.Data == null)
|
||||
@@ -1012,10 +1012,10 @@ namespace SabreTools.Serialization.Extensions
|
||||
// Align to the DWORD boundary if we're not at the end
|
||||
data.AlignToBoundary(ref offset, 4);
|
||||
|
||||
var stringFileInfoChildren = new List<SabreTools.Models.PortableExecutable.Resource.Entries.StringTable>();
|
||||
var stringFileInfoChildren = new List<SabreTools.Serialization.Models.PortableExecutable.Resource.Entries.StringTable>();
|
||||
while ((offset - currentOffset) < stringFileInfo.Length)
|
||||
{
|
||||
var stringTable = new SabreTools.Models.PortableExecutable.Resource.Entries.StringTable();
|
||||
var stringTable = new SabreTools.Serialization.Models.PortableExecutable.Resource.Entries.StringTable();
|
||||
|
||||
stringTable.Length = data.ReadUInt16LittleEndian(ref offset);
|
||||
stringTable.ValueLength = data.ReadUInt16LittleEndian(ref offset);
|
||||
@@ -1069,7 +1069,7 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// </summary>
|
||||
/// <param name="entry">Resource data entry to parse into a string table resource</param>
|
||||
/// <returns>A filled string table resource on success, null on error</returns>
|
||||
public static Dictionary<int, string?>? AsStringTable(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
public static Dictionary<int, string?>? AsStringTable(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
{
|
||||
// If we have an invalid entry, just skip
|
||||
if (entry?.Data == null)
|
||||
@@ -1161,7 +1161,7 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// </summary>
|
||||
/// <param name="entry">Resource data entry to parse into a version info resource</param>
|
||||
/// <returns>A filled version info resource on success, null on error</returns>
|
||||
public static VersionInfo? AsVersionInfo(this SabreTools.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
public static VersionInfo? AsVersionInfo(this SabreTools.Serialization.Models.PortableExecutable.Resource.DataEntry? entry)
|
||||
{
|
||||
// If we have an invalid entry, just skip
|
||||
if (entry?.Data == null)
|
||||
@@ -1358,10 +1358,10 @@ namespace SabreTools.Serialization.Extensions
|
||||
/// <param name="data">Data to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <returns>A filled ResourceHeader on success, null on error</returns>
|
||||
public static SabreTools.Models.PortableExecutable.Resource.ResourceHeader ParseResourceHeader(this byte[] data, ref int offset)
|
||||
public static SabreTools.Serialization.Models.PortableExecutable.Resource.ResourceHeader ParseResourceHeader(this byte[] data, ref int offset)
|
||||
{
|
||||
// Read in the table
|
||||
var obj = new SabreTools.Models.PortableExecutable.Resource.ResourceHeader();
|
||||
var obj = new SabreTools.Serialization.Models.PortableExecutable.Resource.ResourceHeader();
|
||||
|
||||
obj.DataSize = data.ReadUInt32LittleEndian(ref offset);
|
||||
obj.HeaderSize = data.ReadUInt32LittleEndian(ref offset);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
namespace SabreTools.Serialization.Models.AdvancedInstaller
|
||||
{
|
||||
/// <summary>
|
||||
/// Single entry in the file table
|
||||
/// </summary>
|
||||
public class FileEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Observed values:
|
||||
/// - 00 00 00 00 (INI)
|
||||
/// - 01 00 00 00 (MSI, CAB)
|
||||
/// - 05 00 00 00 (DLL)
|
||||
/// </remarks>
|
||||
public uint Unknown0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Observed values:
|
||||
/// - 00 00 00 00 (MSI)
|
||||
/// - 01 00 00 00 (CAB)
|
||||
/// - 03 00 00 00 (INI)
|
||||
/// - 0C 00 00 00 (DLL)
|
||||
/// </remarks>
|
||||
public uint? Unknown1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unknown, always 0?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Observed values:
|
||||
/// - 00 00 00 00 (DLL, MSI, CAB, INI)
|
||||
/// </remarks>
|
||||
public uint? Unknown2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the file
|
||||
/// </summary>
|
||||
public uint FileSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offset of the file relative to the start
|
||||
/// of the SFX stub
|
||||
/// </summary>
|
||||
public uint FileOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the file name in characters
|
||||
/// </summary>
|
||||
public uint NameSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unicode-encoded file name
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
}
|
||||
109
SabreTools.Serialization/Models/AdvancedInstaller/Footer.cs
Normal file
109
SabreTools.Serialization/Models/AdvancedInstaller/Footer.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
namespace SabreTools.Serialization.Models.AdvancedInstaller
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure similar to the end of central directory
|
||||
/// header in PKZIP files
|
||||
/// </summary>
|
||||
public class Footer
|
||||
{
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Observed values:
|
||||
/// - 00 00 00 00
|
||||
/// </remarks>
|
||||
public uint Unknown0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the original filename?
|
||||
/// </summary>
|
||||
/// <remarks>Doesn't exist in some cases?</remarks>
|
||||
public uint? OriginalFilenameSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unicode-encoded original filename?
|
||||
/// </summary>
|
||||
/// <remarks>Doesn't exist in some cases?</remarks>
|
||||
public string? OriginalFilename { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unknown, possibly a string count?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only seen when the preceeding two fields exist
|
||||
///
|
||||
/// Observed values:
|
||||
/// - 01 00 00 00
|
||||
/// </remarks>
|
||||
public uint? Unknown1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to <see cref="Unknown0"/>?
|
||||
/// </summary>
|
||||
public uint FooterOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of entries that preceed the footer
|
||||
/// </summary>
|
||||
public uint EntryCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Observed values:
|
||||
/// - 64 00 00 00
|
||||
/// </remarks>
|
||||
public uint Unknown2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unknown offset
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Points to <see cref="Unknown0"/> if no original filename.
|
||||
/// Points to <see cref="EntryCount"/> if contains an original filename.
|
||||
/// </remarks>
|
||||
public uint UnknownOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offset of the start of the file table
|
||||
/// </summary>
|
||||
public uint TablePointer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offset to the start of the file data
|
||||
/// </summary>
|
||||
public uint FileDataStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Hex string that looks like a key or other identifier
|
||||
/// </summary>
|
||||
/// <remarks>32 bytes</remarks>
|
||||
public string? HexString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Offset pointer to <see cref="FileDataStart"/>
|
||||
/// relative to the end of the signature if no filename
|
||||
/// exists.
|
||||
///
|
||||
/// Observed values:
|
||||
/// - 32 00 00 00 (No original filename)
|
||||
/// - 13 02 00 00 (Original filename)
|
||||
/// </remarks>
|
||||
public uint Unknown3 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// "ADVINSTSFX"
|
||||
/// </summary>
|
||||
public string? Signature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unknown, always 0? Padding?
|
||||
/// </summary>
|
||||
public ushort? Unknown4 { get; set; }
|
||||
}
|
||||
}
|
||||
29
SabreTools.Serialization/Models/AdvancedInstaller/SFX.cs
Normal file
29
SabreTools.Serialization/Models/AdvancedInstaller/SFX.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace SabreTools.Serialization.Models.AdvancedInstaller
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the structure at the end of a Caphyon
|
||||
/// Advanced Installer SFX file. These SFX files store
|
||||
/// all files uncompressed sequentially in the overlay
|
||||
/// of an executable.
|
||||
///
|
||||
/// The design is similar to the end of central directory
|
||||
/// in a PKZIP file. The footer needs to be read before
|
||||
/// the entry table as both the pointer to the start of
|
||||
/// the table as well as the entry count are included there.
|
||||
///
|
||||
/// The layout of this is derived from the layout in the
|
||||
/// physical file.
|
||||
/// </summary>
|
||||
public class SFX
|
||||
{
|
||||
/// <summary>
|
||||
/// Set of file entries
|
||||
/// </summary>
|
||||
public FileEntry[]? Entries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Footer representing the central directory
|
||||
/// </summary>
|
||||
public Footer? Footer { get; set; }
|
||||
}
|
||||
}
|
||||
20
SabreTools.Serialization/Models/COFF/Constants.cs
Normal file
20
SabreTools.Serialization/Models/COFF/Constants.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace SabreTools.Serialization.Models.COFF
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Fixed size of <see cref="FileHeader"/>
|
||||
/// </summary>
|
||||
public const int FileHeaderSize = 20;
|
||||
|
||||
/// <summary>
|
||||
/// Fixed size of <see cref="SectionHeader"/>
|
||||
/// </summary>
|
||||
public const int SectionHeaderSize = 40;
|
||||
|
||||
/// <summary>
|
||||
/// Fixed size of <see cref="SymbolTableEntries.BaseEntry"/>
|
||||
/// </summary>
|
||||
public const int SymbolTableEntrySize = 18;
|
||||
}
|
||||
}
|
||||
1726
SabreTools.Serialization/Models/COFF/Enums.cs
Normal file
1726
SabreTools.Serialization/Models/COFF/Enums.cs
Normal file
File diff suppressed because it is too large
Load Diff
58
SabreTools.Serialization/Models/COFF/FileHeader.cs
Normal file
58
SabreTools.Serialization/Models/COFF/FileHeader.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.COFF
|
||||
{
|
||||
/// <summary>
|
||||
/// At the beginning of an object file, or immediately after the signature
|
||||
/// of an image file, is a standard COFF file header in the following format.
|
||||
/// Note that the Windows loader limits the number of sections to 96.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class FileHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// The number that identifies the type of target machine.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public MachineType Machine;
|
||||
|
||||
/// <summary>
|
||||
/// The number of sections. This indicates the size of the section table,
|
||||
/// which immediately follows the headers.
|
||||
/// </summary>
|
||||
public ushort NumberOfSections;
|
||||
|
||||
/// <summary>
|
||||
/// The low 32 bits of the number of seconds since 00:00 January 1, 1970
|
||||
/// (a C run-time time_t value), which indicates when the file was created.
|
||||
/// </summary>
|
||||
public uint TimeDateStamp;
|
||||
|
||||
/// <summary>
|
||||
/// The file offset of the COFF symbol table, or zero if no COFF symbol table
|
||||
/// is present. This value should be zero for an image because COFF debugging
|
||||
/// information is deprecated.
|
||||
/// </summary>
|
||||
public uint PointerToSymbolTable;
|
||||
|
||||
/// <summary>
|
||||
/// The number of entries in the symbol table. This data can be used to locate
|
||||
/// the string table, which immediately follows the symbol table. This value
|
||||
/// should be zero for an image because COFF debugging information is deprecated.
|
||||
/// </summary>
|
||||
public uint NumberOfSymbols;
|
||||
|
||||
/// <summary>
|
||||
/// The size of the optional header, which is required for executable files but
|
||||
/// not for object files. This value should be zero for an object file.
|
||||
/// </summary>
|
||||
public ushort SizeOfOptionalHeader;
|
||||
|
||||
/// <summary>
|
||||
/// The flags that indicate the attributes of the file.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public Characteristics Characteristics;
|
||||
}
|
||||
}
|
||||
42
SabreTools.Serialization/Models/COFF/LineNumber.cs
Normal file
42
SabreTools.Serialization/Models/COFF/LineNumber.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.COFF
|
||||
{
|
||||
/// <summary>
|
||||
/// COFF line numbers are no longer produced and, in the future, will
|
||||
/// not be consumed.
|
||||
///
|
||||
/// COFF line numbers indicate the relationship between code and line
|
||||
/// numbers in source files. The Microsoft format for COFF line numbers
|
||||
/// is similar to standard COFF, but it has been extended to allow a
|
||||
/// single section to relate to line numbers in multiple source files.
|
||||
///
|
||||
/// COFF line numbers consist of an array of fixed-length records.
|
||||
/// The location (file offset) and size of the array are specified in
|
||||
/// the section header.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public sealed class LineNumber
|
||||
{
|
||||
/// <summary>
|
||||
/// Used when Linenumber is zero: index to symbol table entry for a function.
|
||||
/// This format is used to indicate the function to which a group of
|
||||
/// line-number records refers.
|
||||
/// </summary>
|
||||
[FieldOffset(0)] public uint SymbolTableIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Used when Linenumber is non-zero: the RVA of the executable code that
|
||||
/// corresponds to the source line indicated. In an object file, this
|
||||
/// contains the VA within the section.
|
||||
/// </summary>
|
||||
[FieldOffset(0)] public uint VirtualAddress;
|
||||
|
||||
/// <summary>
|
||||
/// When nonzero, this field specifies a one-based line number. When zero,
|
||||
/// the Type field is interpreted as a symbol table index for a function.
|
||||
/// </summary>
|
||||
[FieldOffset(4)] public ushort Linenumber;
|
||||
}
|
||||
}
|
||||
88
SabreTools.Serialization/Models/COFF/OptionalHeader.cs
Normal file
88
SabreTools.Serialization/Models/COFF/OptionalHeader.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
namespace SabreTools.Serialization.Models.COFF
|
||||
{
|
||||
/// <summary>
|
||||
/// Every image file has an optional header that provides information to the loader.
|
||||
/// This header is optional in the sense that some files (specifically, object files)
|
||||
/// do not have it. For image files, this header is required. An object file can have
|
||||
/// an optional header, but generally this header has no function in an object file
|
||||
/// except to increase its size.
|
||||
///
|
||||
/// Note that the size of the optional header is not fixed. The SizeOfOptionalHeader
|
||||
/// field in the COFF header must be used to validate that a probe into the file for
|
||||
/// a particular data directory does not go beyond SizeOfOptionalHeader.
|
||||
///
|
||||
/// The NumberOfRvaAndSizes field of the optional header should also be used to ensure
|
||||
/// that no probe for a particular data directory entry goes beyond the optional header.
|
||||
/// In addition, it is important to validate the optional header magic number for format
|
||||
/// compatibility.
|
||||
///
|
||||
/// The optional header magic number determines whether an image is a PE32 or
|
||||
/// PE32+ executable.
|
||||
///
|
||||
/// PE32+ images allow for a 64-bit address space while limiting the image size to
|
||||
/// 2 gigabytes. Other PE32+ modifications are addressed in their respective sections.
|
||||
///
|
||||
/// The first eight fields of the optional header are standard fields that are defined
|
||||
/// for every implementation of COFF. These fields contain general information that is
|
||||
/// useful for loading and running an executable file. They are unchanged for the
|
||||
/// PE32+ format.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public class OptionalHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// The unsigned integer that identifies the state of the image file. The most
|
||||
/// common number is 0x10B, which identifies it as a normal executable file.
|
||||
/// 0x107 identifies it as a ROM image, and 0x20B identifies it as a PE32+ executable.
|
||||
/// </summary>
|
||||
public OptionalHeaderMagicNumber Magic { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The linker major version number.
|
||||
/// </summary>
|
||||
public byte MajorLinkerVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The linker minor version number.
|
||||
/// </summary>
|
||||
public byte MinorLinkerVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The size of the code (text) section, or the sum of all code sections if there
|
||||
/// are multiple sections.
|
||||
/// </summary>
|
||||
public uint SizeOfCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The size of the initialized data section, or the sum of all such sections if
|
||||
/// there are multiple data sections.
|
||||
/// </summary>
|
||||
public uint SizeOfInitializedData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The size of the uninitialized data section (BSS), or the sum of all such sections
|
||||
/// if there are multiple BSS sections.
|
||||
/// </summary>
|
||||
public uint SizeOfUninitializedData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address of the entry point relative to the image base when the executable file
|
||||
/// is loaded into memory. For program images, this is the starting address. For
|
||||
/// device drivers, this is the address of the initialization function. An entry point
|
||||
/// is optional for DLLs. When no entry point is present, this field must be zero.
|
||||
/// </summary>
|
||||
public uint AddressOfEntryPoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address that is relative to the image base of the beginning-of-code section when
|
||||
/// it is loaded into memory.
|
||||
/// </summary>
|
||||
public uint BaseOfCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address that is relative to the image base of the beginning-of-data section when
|
||||
/// it is loaded into memory.
|
||||
/// </summary>
|
||||
public uint BaseOfData { get; set; }
|
||||
}
|
||||
}
|
||||
47
SabreTools.Serialization/Models/COFF/Relocation.cs
Normal file
47
SabreTools.Serialization/Models/COFF/Relocation.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.COFF
|
||||
{
|
||||
/// <summary>
|
||||
/// Object files contain COFF relocations, which specify how the section data
|
||||
/// should be modified when placed in the image file and subsequently loaded
|
||||
/// into memory.
|
||||
///
|
||||
/// Image files do not contain COFF relocations, because all referenced symbols
|
||||
/// have already been assigned addresses in a flat address space. An image
|
||||
/// contains relocation information in the form of base relocations in the
|
||||
/// .reloc section (unless the image has the IMAGE_FILE_RELOCS_STRIPPED attribute).
|
||||
///
|
||||
/// For each section in an object file, an array of fixed-length records holds
|
||||
/// the section's COFF relocations. The position and length of the array are
|
||||
/// specified in the section header.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class Relocation
|
||||
{
|
||||
/// <summary>
|
||||
/// The address of the item to which relocation is applied. This is the
|
||||
/// offset from the beginning of the section, plus the value of the
|
||||
/// section's RVA/Offset field. See Section Table (Section Headers).
|
||||
/// For example, if the first byte of the section has an address of 0x10,
|
||||
/// the third byte has an address of 0x12.
|
||||
/// </summary>
|
||||
public uint VirtualAddress;
|
||||
|
||||
/// <summary>
|
||||
/// A zero-based index into the symbol table. This symbol gives the address
|
||||
/// that is to be used for the relocation. If the specified symbol has section
|
||||
/// storage class, then the symbol's address is the address with the first
|
||||
/// section of the same name.
|
||||
/// </summary>
|
||||
public uint SymbolTableIndex;
|
||||
|
||||
/// <summary>
|
||||
/// A value that indicates the kind of relocation that should be performed.
|
||||
/// Valid relocation types depend on machine type.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public RelocationType TypeIndicator;
|
||||
}
|
||||
}
|
||||
111
SabreTools.Serialization/Models/COFF/SectionHeader.cs
Normal file
111
SabreTools.Serialization/Models/COFF/SectionHeader.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
namespace SabreTools.Serialization.Models.COFF
|
||||
{
|
||||
/// <summary>
|
||||
/// Each row of the section table is, in effect, a section header. This table
|
||||
/// immediately follows the optional header, if any. This positioning is required
|
||||
/// because the file header does not contain a direct pointer to the section table.
|
||||
/// Instead, the location of the section table is determined by calculating the
|
||||
/// location of the first byte after the headers. Make sure to use the size of
|
||||
/// the optional header as specified in the file header.
|
||||
///
|
||||
/// The number of entries in the section table is given by the NumberOfSections
|
||||
/// field in the file header. Entries in the section table are numbered starting
|
||||
/// from one (1). The code and data memory section entries are in the order chosen
|
||||
/// by the linker.
|
||||
///
|
||||
/// In an image file, the VAs for sections must be assigned by the linker so that
|
||||
/// they are in ascending order and adjacent, and they must be a multiple of the
|
||||
/// SectionAlignment value in the optional header.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class SectionHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// An 8-byte, null-padded UTF-8 encoded string. If the string is exactly 8
|
||||
/// characters long, there is no terminating null. For longer names, this field
|
||||
/// contains a slash (/) that is followed by an ASCII representation of a
|
||||
/// decimal number that is an offset into the string table. Executable images
|
||||
/// do not use a string table and do not support section names longer than 8
|
||||
/// characters. Long names in object files are truncated if they are emitted
|
||||
/// to an executable file.
|
||||
/// </summary>
|
||||
/// <remarks>8 bytes</remarks>
|
||||
public byte[]? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the section when loaded into memory. If this value is
|
||||
/// greater than SizeOfRawData, the section is zero-padded. This field is valid
|
||||
/// only for executable images and should be set to zero for object files.
|
||||
/// </summary>
|
||||
public uint VirtualSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For executable images, the address of the first byte of the section relative
|
||||
/// to the image base when the section is loaded into memory. For object files,
|
||||
/// this field is the address of the first byte before relocation is applied { get; set; }
|
||||
/// for simplicity, compilers should set this to zero. Otherwise, it is an
|
||||
/// arbitrary value that is subtracted from offsets during relocation.
|
||||
/// </summary>
|
||||
public uint VirtualAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The size of the section (for object files) or the size of the initialized
|
||||
/// data on disk (for image files). For executable images, this must be a multiple
|
||||
/// of FileAlignment from the optional header. If this is less than VirtualSize,
|
||||
/// the remainder of the section is zero-filled. Because the SizeOfRawData field
|
||||
/// is rounded but the VirtualSize field is not, it is possible for SizeOfRawData
|
||||
/// to be greater than VirtualSize as well. When a section contains only
|
||||
/// uninitialized data, this field should be zero.
|
||||
/// </summary>
|
||||
public uint SizeOfRawData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The file pointer to the first page of the section within the COFF file. For
|
||||
/// executable images, this must be a multiple of FileAlignment from the optional
|
||||
/// header. For object files, the value should be aligned on a 4-byte boundary
|
||||
/// for best performance. When a section contains only uninitialized data, this
|
||||
/// field should be zero.
|
||||
/// </summary>
|
||||
public uint PointerToRawData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The file pointer to the beginning of relocation entries for the section. This
|
||||
/// is set to zero for executable images or if there are no relocations.
|
||||
/// </summary>
|
||||
public uint PointerToRelocations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The file pointer to the beginning of line-number entries for the section. This
|
||||
/// is set to zero if there are no COFF line numbers. This value should be zero for
|
||||
/// an image because COFF debugging information is deprecated.
|
||||
/// </summary>
|
||||
public uint PointerToLinenumbers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of relocation entries for the section. This is set to zero for
|
||||
/// executable images.
|
||||
/// </summary>
|
||||
public ushort NumberOfRelocations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of line-number entries for the section. This value should be zero
|
||||
/// for an image because COFF debugging information is deprecated.
|
||||
/// </summary>
|
||||
public ushort NumberOfLinenumbers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The flags that describe the characteristics of the section.
|
||||
/// </summary>
|
||||
public SectionFlags Characteristics { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// COFF Relocations (Object Only)
|
||||
/// </summary>
|
||||
public Relocation[]? COFFRelocations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// COFF Line Numbers (Deprecated)
|
||||
/// </summary>
|
||||
public LineNumber[]? COFFLineNumbers { get; set; }
|
||||
}
|
||||
}
|
||||
25
SabreTools.Serialization/Models/COFF/StringTable.cs
Normal file
25
SabreTools.Serialization/Models/COFF/StringTable.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace SabreTools.Serialization.Models.COFF
|
||||
{
|
||||
/// <summary>
|
||||
/// Immediately following the COFF symbol table is the COFF string table. The
|
||||
/// position of this table is found by taking the symbol table address in the
|
||||
/// COFF header and adding the number of symbols multiplied by the size of a symbol.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class StringTable
|
||||
{
|
||||
/// <summary>
|
||||
/// At the beginning of the COFF string table are 4 bytes that contain the
|
||||
/// total size (in bytes) of the rest of the string table. This size includes
|
||||
/// the size field itself, so that the value in this location would be 4 if no
|
||||
/// strings were present.
|
||||
/// </summary>
|
||||
public uint TotalSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Following the size are null-terminated strings that are pointed to by symbols
|
||||
/// in the COFF symbol table.
|
||||
/// </summary>
|
||||
public string[]? Strings { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
|
||||
{
|
||||
/// <summary>
|
||||
/// The symbol table in this section is inherited from the traditional
|
||||
/// COFF format. It is distinct from Microsoft Visual C++ debug information.
|
||||
/// A file can contain both a COFF symbol table and Visual C++ debug
|
||||
/// information, and the two are kept separate. Some Microsoft tools use
|
||||
/// the symbol table for limited but important purposes, such as
|
||||
/// communicating COMDAT information to the linker. Section names and file
|
||||
/// names, as well as code and data symbols, are listed in the symbol table.
|
||||
///
|
||||
/// The location of the symbol table is indicated in the COFF header.
|
||||
///
|
||||
/// The symbol table is an array of records, each 18 bytes long. Each record
|
||||
/// is either a standard or auxiliary symbol-table record. A standard record
|
||||
/// defines a symbol or name.
|
||||
///
|
||||
/// Auxiliary symbol table records always follow, and apply to, some standard
|
||||
/// symbol table record. An auxiliary record can have any format that the tools
|
||||
/// can recognize, but 18 bytes must be allocated for them so that symbol table
|
||||
/// is maintained as an array of regular size. Currently, Microsoft tools
|
||||
/// recognize auxiliary formats for the following kinds of records: function
|
||||
/// definitions, function begin and end symbols (.bf and .ef), weak externals,
|
||||
/// file names, and section definitions.
|
||||
///
|
||||
/// The traditional COFF design also includes auxiliary-record formats for arrays
|
||||
/// and structures.Microsoft tools do not use these, but instead place that
|
||||
/// symbolic information in Visual C++ debug format in the debug sections.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public abstract class BaseEntry { }
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
|
||||
{
|
||||
/// <summary>
|
||||
/// Auxiliary Format 6: CLR Token Definition (Object Only)
|
||||
///
|
||||
/// This auxiliary symbol generally follows the IMAGE_SYM_CLASS_CLR_TOKEN. It is
|
||||
/// used to associate a token with the COFF symbol table's namespace.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public class CLRTokenDefinition : BaseEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Must be IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF (1).
|
||||
/// </summary>
|
||||
public byte AuxType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, must be zero.
|
||||
/// </summary>
|
||||
public byte Reserved1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The symbol index of the COFF symbol to which this CLR token definition refers.
|
||||
/// </summary>
|
||||
public uint SymbolTableIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reserved, must be zero.
|
||||
/// </summary>
|
||||
/// <remarks>12 bytes</remarks>
|
||||
public byte[]? Reserved2 { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
|
||||
{
|
||||
/// <summary>
|
||||
/// Auxiliary Format 2: .bf and .ef Symbols
|
||||
///
|
||||
/// For each function definition in the symbol table, three items describe
|
||||
/// the beginning, ending, and number of lines. Each of these symbols has
|
||||
/// storage class FUNCTION (101):
|
||||
///
|
||||
/// A symbol record named .bf (begin function). The Value field is unused.
|
||||
///
|
||||
/// A symbol record named .lf (lines in function). The Value field gives the
|
||||
/// number of lines in the function.
|
||||
///
|
||||
/// A symbol record named .ef (end of function). The Value field has the same
|
||||
/// number as the Total Size field in the function-definition symbol record.
|
||||
///
|
||||
// The .bf and .ef symbol records (but not .lf records) are followed by an
|
||||
// auxiliary record with the following format:
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public class Descriptor : BaseEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
public uint Unused1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The actual ordinal line number (1, 2, 3, and so on) within the source file,
|
||||
/// corresponding to the .bf or .ef record.
|
||||
/// </summary>
|
||||
public ushort Linenumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
/// <remarks>6 bytes</remarks>
|
||||
public byte[]? Unused2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The symbol-table index of the next .bf symbol record. If the function is the
|
||||
/// last in the symbol table, this field is set to zero. It is not used for
|
||||
/// .ef records.
|
||||
/// </summary>
|
||||
public uint PointerToNextFunction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
public ushort Unused3 { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
|
||||
{
|
||||
/// <summary>
|
||||
/// Auxiliary Format 4: Files
|
||||
///
|
||||
/// This format follows a symbol-table record with storage class FILE (103).
|
||||
/// The symbol name itself should be .file, and the auxiliary record that
|
||||
/// follows it gives the name of a source-code file.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public class FileRecord : BaseEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// An ANSI string that gives the name of the source file. This is padded
|
||||
/// with nulls if it is less than the maximum length.
|
||||
/// </summary>
|
||||
/// <remarks>18 bytes</remarks>
|
||||
public byte[]? FileName { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
|
||||
{
|
||||
/// <summary>
|
||||
/// Auxiliary Format 1: Function Definitions
|
||||
///
|
||||
/// A symbol table record marks the beginning of a function definition if it
|
||||
/// has all of the following: a storage class of EXTERNAL (2), a Type value
|
||||
/// that indicates it is a function (0x20), and a section number that is
|
||||
/// greater than zero. Note that a symbol table record that has a section
|
||||
/// number of UNDEFINED (0) does not define the function and does not have
|
||||
/// an auxiliary record. Function-definition symbol records are followed by
|
||||
/// an auxiliary record in the format described below:
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public class FunctionDefinition : BaseEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The symbol-table index of the corresponding .bf (begin function)
|
||||
/// symbol record.
|
||||
/// </summary>
|
||||
public uint TagIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The size of the executable code for the function itself. If the function
|
||||
/// is in its own section, the SizeOfRawData in the section header is greater
|
||||
/// or equal to this field, depending on alignment considerations.
|
||||
/// </summary>
|
||||
public uint TotalSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The file offset of the first COFF line-number entry for the function, or
|
||||
/// zero if none exists.
|
||||
/// </summary>
|
||||
public uint PointerToLinenumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The symbol-table index of the record for the next function. If the function
|
||||
/// is the last in the symbol table, this field is set to zero.
|
||||
/// </summary>
|
||||
public uint PointerToNextFunction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
public ushort Unused { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
|
||||
{
|
||||
/// <summary>
|
||||
/// Auxiliary Format 5: Section Definitions
|
||||
///
|
||||
/// This format follows a symbol-table record that defines a section. Such a
|
||||
/// record has a symbol name that is the name of a section (such as .text or
|
||||
/// .drectve) and has storage class STATIC (3). The auxiliary record provides
|
||||
/// information about the section to which it refers. Thus, it duplicates some
|
||||
/// of the information in the section header.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public class SectionDefinition : BaseEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The size of section data; the same as SizeOfRawData in the section header.
|
||||
/// </summary>
|
||||
public uint Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of relocation entries for the section.
|
||||
/// </summary>
|
||||
public ushort NumberOfRelocations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of line-number entries for the section.
|
||||
/// </summary>
|
||||
public ushort NumberOfLinenumbers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The checksum for communal data. It is applicable if the IMAGE_SCN_LNK_COMDAT
|
||||
/// flag is set in the section header.
|
||||
/// </summary>
|
||||
public uint CheckSum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// One-based index into the section table for the associated section. This is
|
||||
/// used when the COMDAT selection setting is 5.
|
||||
/// </summary>
|
||||
public ushort Number { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The COMDAT selection number. This is applicable if the section is a
|
||||
/// COMDAT section.
|
||||
/// </summary>
|
||||
public byte Selection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
/// <remarks>3 bytes</remarks>
|
||||
public byte[]? Unused { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
|
||||
{
|
||||
/// <summary>
|
||||
/// A standard record defines a symbol or name.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public class StandardRecord : BaseEntry
|
||||
{
|
||||
#region Symbol Name
|
||||
|
||||
/// <summary>
|
||||
/// An array of 8 bytes. This array is padded with nulls on the right if
|
||||
/// the name is less than 8 bytes long.
|
||||
/// </summary>
|
||||
public byte[]? ShortName { get; set; } = new byte[8];
|
||||
|
||||
/// <summary>
|
||||
/// A field that is set to all zeros if the name is longer than 8 bytes.
|
||||
/// </summary>
|
||||
public uint Zeroes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An offset into the string table.
|
||||
/// </summary>
|
||||
public uint Offset { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The value that is associated with the symbol. The interpretation of this
|
||||
/// field depends on SectionNumber and StorageClass. A typical meaning is the
|
||||
/// relocatable address.
|
||||
/// </summary>
|
||||
public uint Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The signed integer that identifies the section, using a one-based index
|
||||
/// into the section table. Some values have special meaning.
|
||||
/// </summary>
|
||||
public SectionNumber SectionNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A number that represents type. Microsoft tools set this field to 0x20
|
||||
/// (function) or 0x0 (not a function).
|
||||
/// </summary>
|
||||
public SymbolType SymbolType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An enumerated value that represents storage class.
|
||||
/// </summary>
|
||||
public StorageClass StorageClass { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of auxiliary symbol table entries that follow this record.
|
||||
/// </summary>
|
||||
public byte NumberOfAuxSymbols { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
namespace SabreTools.Serialization.Models.COFF.SymbolTableEntries
|
||||
{
|
||||
/// <summary>
|
||||
/// Auxiliary Format 3: Weak Externals
|
||||
///
|
||||
/// "Weak externals" are a mechanism for object files that allows flexibility at
|
||||
/// link time. A module can contain an unresolved external symbol (sym1), but it
|
||||
/// can also include an auxiliary record that indicates that if sym1 is not
|
||||
/// present at link time, another external symbol (sym2) is used to resolve
|
||||
/// references instead.
|
||||
///
|
||||
/// If a definition of sym1 is linked, then an external reference to the symbol
|
||||
/// is resolved normally. If a definition of sym1 is not linked, then all references
|
||||
/// to the weak external for sym1 refer to sym2 instead. The external symbol, sym2,
|
||||
/// must always be linked; typically, it is defined in the module that contains
|
||||
/// the weak reference to sym1.
|
||||
///
|
||||
/// Weak externals are represented by a symbol table record with EXTERNAL storage
|
||||
/// class, UNDEF section number, and a value of zero. The weak-external symbol
|
||||
/// record is followed by an auxiliary record with the following format:
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public class WeakExternal : BaseEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The symbol-table index of sym2, the symbol to be linked if sym1 is not found.
|
||||
/// </summary>
|
||||
public uint TagIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A value of IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY indicates that no library search
|
||||
/// for sym1 should be performed.
|
||||
/// A value of IMAGE_WEAK_EXTERN_SEARCH_LIBRARY indicates that a library search for
|
||||
/// sym1 should be performed.
|
||||
/// A value of IMAGE_WEAK_EXTERN_SEARCH_ALIAS indicates that sym1 is an alias for sym2.
|
||||
/// </summary>
|
||||
public uint Characteristics { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unused
|
||||
/// </summary>
|
||||
/// <remarks>10 bytes</remarks>
|
||||
public byte[]? Unused { get; set; }
|
||||
}
|
||||
}
|
||||
14
SabreTools.Serialization/Models/Delphi/Constants.cs
Normal file
14
SabreTools.Serialization/Models/Delphi/Constants.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
/// <remarks>
|
||||
/// Information sourced from https://stackoverflow.com/questions/18720045/what-are-the-list-of-all-possible-values-for-dvclal
|
||||
/// </remarks>
|
||||
namespace SabreTools.Serialization.Models.Delphi
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly byte[] DVCLALStandard = [0x23, 0x78, 0x5D, 0x23, 0xB6, 0xA5, 0xF3, 0x19, 0x43, 0xF3, 0x40, 0x02, 0x26, 0xD1, 0x11, 0xC7];
|
||||
|
||||
public static readonly byte[] DVCLALProfessional = [0xA2, 0x8C, 0xDF, 0x98, 0x7B, 0x3C, 0x3A, 0x79, 0x26, 0x71, 0x3F, 0x09, 0x0F, 0x2A, 0x25, 0x17];
|
||||
|
||||
public static readonly byte[] DVCLALEnterprise = [0x26, 0x3D, 0x4F, 0x38, 0xC2, 0x82, 0x37, 0xB8, 0xF3, 0x24, 0x42, 0x03, 0x17, 0x9B, 0x3A, 0x83];
|
||||
}
|
||||
}
|
||||
14
SabreTools.Serialization/Models/Delphi/PackageInfoTable.cs
Normal file
14
SabreTools.Serialization/Models/Delphi/PackageInfoTable.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
/// <remarks>
|
||||
/// Information sourced from https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.PackageInfoTable
|
||||
/// </remarks>
|
||||
namespace SabreTools.Serialization.Models.Delphi
|
||||
{
|
||||
public class PackageInfoTable
|
||||
{
|
||||
public int UnitCount { get; set; }
|
||||
|
||||
public PackageUnitEntry[]? UnitInfo { get; set; }
|
||||
|
||||
public PackageTypeInfo? TypeInfo { get; set; }
|
||||
}
|
||||
}
|
||||
19
SabreTools.Serialization/Models/Delphi/PackageTypeInfo.cs
Normal file
19
SabreTools.Serialization/Models/Delphi/PackageTypeInfo.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
/// <remarks>
|
||||
/// Information sourced from https://docwiki.embarcadero.com/Libraries/Sydney/en/System.TPackageTypeInfo
|
||||
/// </remarks>
|
||||
namespace SabreTools.Serialization.Models.Delphi
|
||||
{
|
||||
public class PackageTypeInfo
|
||||
{
|
||||
public int TypeCount { get; set; }
|
||||
|
||||
/// <remarks>
|
||||
/// System-dependent pointer type, assumed to be encoded for x86
|
||||
/// </remarks>
|
||||
public uint[]? TypeTable { get; set; }
|
||||
|
||||
public int UnitCount { get; set; }
|
||||
|
||||
public string[]? UnitNames { get; set; }
|
||||
}
|
||||
}
|
||||
21
SabreTools.Serialization/Models/Delphi/PackageUnitEntry.cs
Normal file
21
SabreTools.Serialization/Models/Delphi/PackageUnitEntry.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <remarks>
|
||||
/// Information sourced from https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.PackageUnitEntry
|
||||
/// </remarks>
|
||||
namespace SabreTools.Serialization.Models.Delphi
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class PackageUnitEntry
|
||||
{
|
||||
/// <remarks>
|
||||
/// System-dependent pointer type, assumed to be encoded for x86
|
||||
/// </remarks>
|
||||
public uint Init;
|
||||
|
||||
/// <remarks>
|
||||
/// System-dependent pointer type, assumed to be encoded for x86
|
||||
/// </remarks>
|
||||
public uint FInit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly byte[] DebugInformationSignatureBytes = [0x4e, 0x42, 0x30];
|
||||
|
||||
public const string DebugInformationSignatureString = "NB0";
|
||||
|
||||
public static readonly byte[] LESignatureBytes = [0x4c, 0x45];
|
||||
|
||||
public const string LESignatureString = "LE";
|
||||
|
||||
public const ushort LESignatureUInt16 = 0x454c;
|
||||
|
||||
public static readonly byte[] LXSignatureBytes = [0x4c, 0x58];
|
||||
|
||||
public const string LXSignatureString = "LX";
|
||||
|
||||
public const ushort LXSignatureUInt16 = 0x584c;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The debug information is defined by the debugger and is not controlled by
|
||||
/// the linear EXE format or linker. The only data defined by the linear EXE
|
||||
/// format relative to the debug information is it's offset in the EXE file and
|
||||
/// length in bytes as defined in the linear EXE header.
|
||||
///
|
||||
/// To support multiple debuggers the first word of the debug information is a
|
||||
/// type field which determines the format of the debug information.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
public sealed class DebugInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// The signature consists of a string of three (3) ASCII characters: "NB0"
|
||||
/// </summary>
|
||||
public string? Signature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This defines the type of debugger data that exists in the remainder of the
|
||||
/// debug information.
|
||||
/// </summary>
|
||||
public DebugFormatType FormatType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The format of the debugger data is defined by the debugger that is being used.
|
||||
/// The values defined for the type field are not enforced by the system. It is
|
||||
/// the responsibility of the linker or debugging tools to follow the convention
|
||||
/// for the type field that is defined here.
|
||||
/// </summary>
|
||||
public byte[]? DebuggerData { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry table contains object and offset information that is used to resolve
|
||||
/// fixup references to the entry points within this module. Not all entry points
|
||||
/// in the entry table will be exported, some entry points will only be used
|
||||
/// within the module. An ordinal number is used to index into the entry table.
|
||||
/// The entry table entries are numbered starting from one.
|
||||
///
|
||||
/// The list of entries are compressed into 'bundles', where possible. The entries
|
||||
/// within each bundle are all the same size. A bundle starts with a count field
|
||||
/// which indicates the number of entries in the bundle. The count is followed by
|
||||
/// a type field which identifies the bundle format. This provides both a means
|
||||
/// for saving space as well as a mechanism for extending the bundle types.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
public sealed class EntryTableBundle
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of entries.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the number of entries in this bundle.
|
||||
///
|
||||
/// A zero value for the number of entries identifies the end of the
|
||||
/// entry table. There is no further bundle information when the number
|
||||
/// of entries is zero. In other words the entry table is terminated by
|
||||
/// a single zero byte.
|
||||
///
|
||||
/// For <see cref="BundleType.UnusedEntry"/>, this is the number of unused
|
||||
/// entries to skip.
|
||||
/// For <see cref="BundleType.SixteenBitEntry"/>, this is the number of 16-bit
|
||||
/// entries in this bundle. The flags and offset value are repeated this
|
||||
/// number of times.
|
||||
/// For <see cref="BundleType.TwoEightySixCallGateEntry"/>, this is the number
|
||||
/// of 286 call gate entries in this bundle. The flags, callgate, and offset
|
||||
/// value are repeated this number of times.
|
||||
/// For <see cref="BundleType.ThirtyTwoBitEntry"/>, this is the number
|
||||
/// of 32-bit entries in this bundle. The flags and offset value are repeated
|
||||
/// this number of times.
|
||||
/// For <see cref="BundleType.ForwarderEntry"/>, this field is reserved for future use.
|
||||
/// </remarks>
|
||||
public byte Entries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This defines the bundle type which determines the contents of the BUNDLE INFO.
|
||||
/// </summary>
|
||||
public BundleType BundleType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Table entries in the bundle
|
||||
/// </summary>
|
||||
public EntryTableEntry[]? TableEntries { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public sealed class EntryTableEntry
|
||||
{
|
||||
#region 16-bit Entry
|
||||
|
||||
/// <summary>
|
||||
/// Object number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the object number for the entries in this bundle.
|
||||
/// </remarks>
|
||||
[FieldOffset(0)] public ushort SixteenBitObjectNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Entry flags.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These are the flags for this entry point.
|
||||
/// </remarks>
|
||||
[FieldOffset(2)] public EntryFlags SixteenBitEntryFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Offset in object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the offset in the object for the entry point defined at this ordinal number.
|
||||
/// </remarks>
|
||||
[FieldOffset(3)] public ushort SixteenBitOffset;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 286 Call Gate Entry
|
||||
|
||||
/// <summary>
|
||||
/// Object number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the object number for the entries in this bundle.
|
||||
/// </remarks>
|
||||
[FieldOffset(0)] public ushort TwoEightySixObjectNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Entry flags.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These are the flags for this entry point.
|
||||
/// </remarks>
|
||||
[FieldOffset(2)] public EntryFlags TwoEightySixEntryFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Offset in object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the offset in the object for the entry point defined at this ordinal number.
|
||||
/// </remarks>
|
||||
[FieldOffset(3)] public ushort TwoEightySixOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Callgate selector.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The callgate selector is a reserved field used by the loader to store a call
|
||||
/// gate selector value for references to ring 2 entry points. When a ring 3
|
||||
/// reference to a ring 2 entry point is made, the callgate selector with a zero
|
||||
/// offset is place in the relocation fixup address. The segment number and offset
|
||||
/// in segment is placed in the LDT callgate.
|
||||
/// </remarks>
|
||||
[FieldOffset(5)] public ushort TwoEightySixCallgate;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 32-bit Entry
|
||||
|
||||
/// <summary>
|
||||
/// Object number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the object number for the entries in this bundle.
|
||||
/// </remarks>
|
||||
[FieldOffset(0)] public ushort ThirtyTwoBitObjectNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Entry flags.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These are the flags for this entry point.
|
||||
/// </remarks>
|
||||
[FieldOffset(2)] public EntryFlags ThirtyTwoBitEntryFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Offset in object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the offset in the object for the entry point defined at this ordinal number.
|
||||
/// </remarks>
|
||||
[FieldOffset(3)] public uint ThirtyTwoBitOffset;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Forwarder Entry
|
||||
|
||||
/// <summary>
|
||||
/// 0
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field is reserved for future use.
|
||||
/// </remarks>
|
||||
[FieldOffset(0)] public ushort ForwarderReserved;
|
||||
|
||||
/// <summary>
|
||||
/// Forwarder flags.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// These are the flags for this entry point.
|
||||
/// </remarks>
|
||||
[FieldOffset(2)] public ForwarderFlags ForwarderFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Module Ordinal Number
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the index into the Import Module Name Table for this forwarder.
|
||||
/// </remarks>
|
||||
[FieldOffset(3)] public ushort ForwarderModuleOrdinalNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Procedure Name Offset
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the FLAGS field indicates import by ordinal, then this field is the
|
||||
/// ordinal number into the Entry Table of the target module, otherwise this
|
||||
/// field is the offset into the Procedure Names Table of the target module.
|
||||
///
|
||||
/// A Forwarder entry (type = 4) is an entry point whose value is an imported
|
||||
/// reference. When a load time fixup occurs whose target is a forwarder, the
|
||||
/// loader obtains the address imported by the forwarder and uses that imported
|
||||
/// address to resolve the fixup.
|
||||
///
|
||||
/// A forwarder may refer to an entry point in another module which is itself a
|
||||
/// forwarder, so there can be a chain of forwarders. The loader will traverse
|
||||
/// the chain until it finds a non-forwarded entry point which terminates the
|
||||
/// chain, and use this to resolve the original fixup. Circular chains are
|
||||
/// detected by the loader and result in a load time error. A maximum of 1024
|
||||
/// forwarders is allowed in a chain; more than this results in a load time error.
|
||||
///
|
||||
/// Forwarders are useful for merging and recombining API calls into different
|
||||
/// sets of libraries, while maintaining compatibility with applications. For
|
||||
/// example, if one wanted to combine MONCALLS, MOUCALLS, and VIOCALLS into a
|
||||
/// single libraries, one could provide entry points for the three libraries
|
||||
/// that are forwarders pointing to the common implementation.
|
||||
/// </remarks>
|
||||
[FieldOffset(5)] public uint ProcedureNameOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Import Ordinal Number
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the FLAGS field indicates import by ordinal, then this field is the
|
||||
/// ordinal number into the Entry Table of the target module, otherwise this
|
||||
/// field is the offset into the Procedure Names Table of the target module.
|
||||
///
|
||||
/// A Forwarder entry (type = 4) is an entry point whose value is an imported
|
||||
/// reference. When a load time fixup occurs whose target is a forwarder, the
|
||||
/// loader obtains the address imported by the forwarder and uses that imported
|
||||
/// address to resolve the fixup.
|
||||
///
|
||||
/// A forwarder may refer to an entry point in another module which is itself a
|
||||
/// forwarder, so there can be a chain of forwarders. The loader will traverse
|
||||
/// the chain until it finds a non-forwarded entry point which terminates the
|
||||
/// chain, and use this to resolve the original fixup. Circular chains are
|
||||
/// detected by the loader and result in a load time error. A maximum of 1024
|
||||
/// forwarders is allowed in a chain; more than this results in a load time error.
|
||||
///
|
||||
/// Forwarders are useful for merging and recombining API calls into different
|
||||
/// sets of libraries, while maintaining compatibility with applications. For
|
||||
/// example, if one wanted to combine MONCALLS, MOUCALLS, and VIOCALLS into a
|
||||
/// single libraries, one could provide entry points for the three libraries
|
||||
/// that are forwarders pointing to the common implementation.
|
||||
/// </remarks>
|
||||
[FieldOffset(5)] public uint ImportOrdinalNumber;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
680
SabreTools.Serialization/Models/LinearExecutable/Enums.cs
Normal file
680
SabreTools.Serialization/Models/LinearExecutable/Enums.cs
Normal file
@@ -0,0 +1,680 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
[Flags]
|
||||
public enum BundleType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Unused Entry.
|
||||
/// </summary>
|
||||
UnusedEntry = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// 16-bit Entry.
|
||||
/// </summary>
|
||||
SixteenBitEntry = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// 286 Call Gate Entry.
|
||||
/// </summary>
|
||||
TwoEightySixCallGateEntry = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit Entry.
|
||||
/// </summary>
|
||||
ThirtyTwoBitEntry = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// Forwarder Entry.
|
||||
/// </summary>
|
||||
ForwarderEntry = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// Parameter Typing Information Present.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This bit signifies that additional information is contained in the
|
||||
/// linear EXE module and will be used in the future for parameter type checking.
|
||||
/// </remarks>
|
||||
ParameterTypingInformationPresent = 0x80,
|
||||
}
|
||||
|
||||
public enum ByteOrder : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// little-endian
|
||||
/// </summary>
|
||||
LE = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// big-endian
|
||||
/// </summary>
|
||||
/// <remarks>non-zero</remarks>
|
||||
BE = 0x01,
|
||||
}
|
||||
|
||||
public enum CPUType : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Intel 80286 or upwardly compatible
|
||||
/// </summary>
|
||||
Intel80286 = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Intel 80386 or upwardly compatible
|
||||
/// </summary>
|
||||
Intel80386 = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// Intel 80486 or upwardly compatible
|
||||
/// </summary>
|
||||
Intel80486 = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// Intel 80586 or upwardly compatible
|
||||
/// </summary>
|
||||
Intel80586 = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// Intel i860 (N10) or compatible
|
||||
/// </summary>
|
||||
Inteli860 = 0x20,
|
||||
|
||||
/// <summary>
|
||||
/// Intel "N11" or compatible
|
||||
/// </summary>
|
||||
IntelN11 = 0x21,
|
||||
|
||||
/// <summary>
|
||||
/// MIPS Mark I (R2000, R3000) or compatible
|
||||
/// </summary>
|
||||
MIPSMarkI = 0x40,
|
||||
|
||||
/// <summary>
|
||||
/// MIPS Mark II ( R6000 ) or compatible
|
||||
/// </summary>
|
||||
MIPSMarkII = 0x41,
|
||||
|
||||
/// <summary>
|
||||
/// MIPS Mark III ( R4000 ) or compatible
|
||||
/// </summary>
|
||||
MIPSMarkIII = 0x42,
|
||||
}
|
||||
|
||||
public enum DebugFormatType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 32-bit CodeView debugger format.
|
||||
/// </summary>
|
||||
CodeView32Bit = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// AIX debugger format.
|
||||
/// </summary>
|
||||
AIXDebugger = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// 16-bit CodeView debugger format.
|
||||
/// </summary>
|
||||
CodeView16Bit = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit OS/2 PM debugger (IBM) format.
|
||||
/// </summary>
|
||||
OS2PM32Bit = 0x04,
|
||||
}
|
||||
|
||||
public enum DirectiveNumber : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Resident Flag Mask.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Directive numbers with this bit set indicate that the directive data
|
||||
/// is in the resident area and will be kept resident in memory when the
|
||||
/// module is loaded.
|
||||
/// </remarks>
|
||||
ResidentFlagMask = 0x8000,
|
||||
|
||||
/// <summary>
|
||||
/// Verify Record Directive. (Verify record is a resident table.)
|
||||
/// </summary>
|
||||
VerifyRecordDirective = 0x8001,
|
||||
|
||||
/// <summary>
|
||||
/// Language Information Directive. (This is a non-resident table.)
|
||||
/// </summary>
|
||||
LanguageInformationDirective = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// Co-Processor Required Support Table.
|
||||
/// </summary>
|
||||
CoProcessorRequiredSupportTable = 0x0003,
|
||||
|
||||
/// <summary>
|
||||
/// Thread State Initialization Directive.
|
||||
/// </summary>
|
||||
ThreadStateInitializationDirective = 0x0004,
|
||||
|
||||
// Additional directives can be added as needed in the future, as long as
|
||||
// they do not overlap previously defined directive numbers.
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum EntryFlags : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Exported entry flag.
|
||||
/// </summary>
|
||||
ExportedEntry = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Parameter word count mask.
|
||||
/// </summary>
|
||||
ParameterWordCountMask = 0xF8,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum FixupRecordSourceType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Source mask.
|
||||
/// </summary>
|
||||
SourceMask = 0x0F,
|
||||
|
||||
/// <summary>
|
||||
/// Byte fixup (8-bits).
|
||||
/// </summary>
|
||||
ByteFixup = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// (undefined).
|
||||
/// </summary>
|
||||
Undefined1 = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// 16-bit Selector fixup (16-bits).
|
||||
/// </summary>
|
||||
SixteenBitSelectorFixup = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// 16:16 Pointer fixup (32-bits).
|
||||
/// </summary>
|
||||
SixteenSixteenPointerFixup = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// (undefined).
|
||||
/// </summary>
|
||||
Undefined4 = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// 16-bit Offset fixup (16-bits).
|
||||
/// </summary>
|
||||
SixteenBitOffsetFixup = 0x05,
|
||||
|
||||
/// <summary>
|
||||
/// 16:32 Pointer fixup (48-bits).
|
||||
/// </summary>
|
||||
SixteenThirtyTwoPointerFixup = 0x06,
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit Offset fixup (32-bits).
|
||||
/// </summary>
|
||||
ThirtyTwoBitOffsetFixup = 0x07,
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit Self-relative offset fixup (32-bits).
|
||||
/// </summary>
|
||||
ThirtyTwoBitSelfRelativeOffsetFixup = 0x08,
|
||||
|
||||
/// <summary>
|
||||
/// Fixup to Alias Flag.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the 'Fixup to Alias' Flag is set, the source fixup refers to
|
||||
/// the 16:16 alias for the object. This is only valid for source types
|
||||
/// of 2, 3, and 6. For fixups such as this, the linker and loader will
|
||||
/// be required to perform additional checks such as ensuring that the
|
||||
/// target offset for this fixup is less than 64K.
|
||||
/// </remarks>
|
||||
FixupToAliasFlag = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// Source List Flag.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the 'Source List' Flag is set, the SRCOFF field is compressed
|
||||
/// to a byte and contains the number of source offsets, and a list of source
|
||||
/// offsets follows the end of fixup record (after the optional additive value).
|
||||
/// </remarks>
|
||||
SourceListFlag = 0x20,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum FixupRecordTargetFlags : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Fixup target type mask.
|
||||
/// </summary>
|
||||
FixupTargetTypeMask = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// Internal reference.
|
||||
/// </summary>
|
||||
InternalReference = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// Imported reference by ordinal.
|
||||
/// </summary>
|
||||
ImportedReferenceByOrdinal = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Imported reference by name.
|
||||
/// </summary>
|
||||
ImportedReferenceByName = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// Internal reference via entry table.
|
||||
/// </summary>
|
||||
InternalReferenceViaEntryTable = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// Additive Fixup Flag.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When set, an additive value trails the fixup record (before the optional
|
||||
/// source offset list).
|
||||
/// </remarks>
|
||||
AdditiveFixupFlag = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved. Must be zero.
|
||||
/// </summary>
|
||||
Reserved = 0x08,
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit Target Offset Flag.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When set, the target offset is 32-bits, otherwise it is 16-bits.
|
||||
/// </remarks>
|
||||
ThirtyTwoBitTargetOffsetFlag = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit Additive Fixup Flag.
|
||||
/// </summary>
|
||||
/// When set, the additive value is 32-bits, otherwise it is 16-bits.
|
||||
/// </remarks>
|
||||
ThirtyTwoBitAdditiveFixupFlag = 0x20,
|
||||
|
||||
/// <summary>
|
||||
/// 16-bit Object Number/Module Ordinal Flag.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When set, the object number or module ordinal number is 16-bits,
|
||||
/// otherwise it is 8-bits.
|
||||
/// </remarks>
|
||||
SixteenBitObjectNumberModuleOrdinalFlag = 0x40,
|
||||
|
||||
/// <summary>
|
||||
/// 8-bit Ordinal Flag.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When set, the ordinal number is 8-bits, otherwise it is 16-bits.
|
||||
/// </remarks>
|
||||
EightBitOrdinalFlag = 0x80,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ForwarderFlags : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Import by ordinal.
|
||||
/// </summary>
|
||||
ImportByOrdinal = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use; should be zero.
|
||||
/// </summary>
|
||||
Reserved = 0xF7,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ModuleFlags : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved for system use.
|
||||
/// </summary>
|
||||
Reserved0 = 0x00000001,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for system use.
|
||||
/// </summary>
|
||||
Reserved1 = 0x00000002,
|
||||
|
||||
/// <summary>
|
||||
/// Per-Process Library Initialization.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The setting of this bit requires the EIP Object # and EIP fields
|
||||
/// to have valid values. If the EIP Object # and EIP fields are
|
||||
/// valid and this bit is NOT set, then Global Library Initialization
|
||||
/// is assumed. Setting this bit for an EXE file is invalid.
|
||||
/// </remarks>
|
||||
Initialization = 0x00000004,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for system use.
|
||||
/// </summary>
|
||||
Reserved3 = 0x00000008,
|
||||
|
||||
/// <summary>
|
||||
/// Internal fixups for the module have been applied.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The setting of this bit in a Linear Executable Module indicates that
|
||||
/// each object of the module has a preferred load address specified in
|
||||
/// the Object Table Reloc Base Addr. If the module's objects can not be
|
||||
/// loaded at these preferred addresses, then the relocation records that
|
||||
/// have been retained in the file data will be applied.
|
||||
/// </remarks>
|
||||
InternalFixupsApplied = 0x00000010,
|
||||
|
||||
/// <summary>
|
||||
/// External fixups for the module have been applied.
|
||||
/// </summary>
|
||||
ExternalFixupsApplied = 0x00000020,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for system use.
|
||||
/// </summary>
|
||||
Reserved6 = 0x00000040,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for system use.
|
||||
/// </summary>
|
||||
Reserved7 = 0x00000080,
|
||||
|
||||
/// <summary>
|
||||
/// Incompatible with PM windowing.
|
||||
/// </summary>
|
||||
IncompatibleWithPMWindowing = 0x00000100,
|
||||
|
||||
/// <summary>
|
||||
/// Incompatible with PM windowing.
|
||||
/// </summary>
|
||||
CompatibleWithPMWindowing = 0x00000200,
|
||||
|
||||
/// <summary>
|
||||
/// Uses PM windowing API.
|
||||
/// </summary>
|
||||
UsesPMWindowing = 0x00000300,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for system use.
|
||||
/// </summary>
|
||||
Reserved10 = 0x00000400,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for system use.
|
||||
/// </summary>
|
||||
Reserved11 = 0x00000800,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for system use.
|
||||
/// </summary>
|
||||
Reserved12 = 0x00001000,
|
||||
|
||||
/// <summary>
|
||||
/// Module is not loadable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the 'Module is not loadable' flag is set, it indicates that
|
||||
/// either errors were detected at link time or that the module is
|
||||
/// being incrementally linked and therefore can't be loaded.
|
||||
/// </remarks>
|
||||
ModuleNotLoadable = 0x00002000,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for system use.
|
||||
/// </summary>
|
||||
Reserved14 = 0x00004000,
|
||||
|
||||
/// <summary>
|
||||
/// Module type mask.
|
||||
/// </summary>
|
||||
ModuleTypeMask = 0x00038000,
|
||||
|
||||
/// <summary>
|
||||
/// Program module.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A module can not contain dynamic links to other modules that have
|
||||
/// the 'program module' type.
|
||||
/// </remarks>
|
||||
ProgramModule = 0x00000000,
|
||||
|
||||
/// <summary>
|
||||
/// Library module.
|
||||
/// </summary>
|
||||
LibraryModule = 0x00008000,
|
||||
|
||||
/// <summary>
|
||||
/// Protected Memory Library module.
|
||||
/// </summary>
|
||||
ProtectedMemoryLibraryModule = 0x00018000,
|
||||
|
||||
/// <summary>
|
||||
/// Physical Device Driver module.
|
||||
/// </summary>
|
||||
PhysicalDeviceDriverModule = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// Virtual Device Driver module.
|
||||
/// </summary>
|
||||
VirtualDeviceDriverModule = 0x00028000,
|
||||
|
||||
/// <summary>
|
||||
/// Per-process Library Termination.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The setting of this bit requires the EIP Object # and EIP fields
|
||||
/// to have valid values. If the EIP Object # and EIP fields are
|
||||
/// valid and this bit is NOT set, then Global Library Termination
|
||||
/// is assumed. Setting this bit for an EXE file is invalid.
|
||||
/// </remarks>
|
||||
PerProcessLibraryTermination = 0x40000000,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ObjectFlags : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Readable Object.
|
||||
/// </summary>
|
||||
ReadableObject = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// Writable Object.
|
||||
/// </summary>
|
||||
WritableObject = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// Executable Object.
|
||||
/// </summary>
|
||||
ExecutableObject = 0x0004,
|
||||
|
||||
// The readable, writable and executable flags provide support for all possible
|
||||
// protections. In systems where all of these protections are not supported,
|
||||
// the loader will be responsible for making the appropriate protection match
|
||||
// for the system.
|
||||
|
||||
/// <summary>
|
||||
/// Resource Object.
|
||||
/// </summary>
|
||||
ResourceObject = 0x0008,
|
||||
|
||||
/// <summary>
|
||||
/// Discardable Object.
|
||||
/// </summary>
|
||||
DiscardableObject = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// Object is Shared.
|
||||
/// </summary>
|
||||
Shared = 0x0020,
|
||||
|
||||
/// <summary>
|
||||
/// Object has Preload Pages.
|
||||
/// </summary>
|
||||
HasPreloadPages = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// Object has Invalid Pages.
|
||||
/// </summary>
|
||||
HasInvalidPages = 0x0080,
|
||||
|
||||
/// <summary>
|
||||
/// Object has Zero Filled Pages.
|
||||
/// </summary>
|
||||
HasZeroFilledPages = 0x0100,
|
||||
|
||||
/// <summary>
|
||||
/// Object is Resident (valid for VDDs, PDDs only).
|
||||
/// </summary>
|
||||
Resident = 0x0200,
|
||||
|
||||
/// <summary>
|
||||
/// Object is Resident & Contiguous (VDDs, PDDs only).
|
||||
/// </summary>
|
||||
ResidentAndContiguous = 0x0300,
|
||||
|
||||
/// <summary>
|
||||
/// Object is Resident & 'long-lockable' (VDDs, PDDs only).
|
||||
/// </summary>
|
||||
ResidentAndLongLockable = 0x0400,
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for system use.
|
||||
/// </summary>
|
||||
Reserved = 0x0800,
|
||||
|
||||
/// <summary>
|
||||
/// 16:16 Alias Required (80x86 Specific).
|
||||
/// </summary>
|
||||
AliasRequired = 0x1000,
|
||||
|
||||
/// <summary>
|
||||
/// Big/Default Bit Setting (80x86 Specific).
|
||||
/// </summary>
|
||||
BitSetting = 0x2000,
|
||||
|
||||
// The 'big/default' bit, for data segments, controls the setting of the
|
||||
// Big bit in the segment descriptor. (The Big bit, or B-bit, determines
|
||||
// whether ESP or SP is used as the stack pointer.) For code segments,
|
||||
// this bit controls the setting of the Default bit in the segment
|
||||
// descriptor. (The Default bit, or D-bit, determines whether the default
|
||||
// word size is 32-bits or 16-bits. It also affects the interpretation of
|
||||
// the instruction stream.)
|
||||
|
||||
/// <summary>
|
||||
/// Object is conforming for code (80x86 Specific).
|
||||
/// </summary>
|
||||
Conforming = 0x4000,
|
||||
|
||||
/// <summary>
|
||||
/// Object I/O privilege level (80x86 Specific). Only used for 16:16 Alias Objects.
|
||||
/// </summary>
|
||||
PrivilegeLevel = 0x8000,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ObjectPageFlags : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Legal Physical Page in the module (Offset from Preload Page Section).
|
||||
/// </summary>
|
||||
LegalPhysicalPage = 0x0000,
|
||||
|
||||
/// <summary>
|
||||
/// Iterated Data Page (Offset from Iterated Data Pages Section).
|
||||
/// </summary>
|
||||
IteratedDataPage = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// Invalid Page (zero).
|
||||
/// </summary>
|
||||
InvalidPage = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// Zero Filled Page (zero).
|
||||
/// </summary>
|
||||
ZeroFilledPage = 0x0003,
|
||||
|
||||
/// <summary>
|
||||
/// Range of Pages.
|
||||
/// </summary>
|
||||
RangeOfPages = 0x0004,
|
||||
}
|
||||
|
||||
public enum OperatingSystem : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Unknown (any "new-format" OS)
|
||||
/// </summary>
|
||||
Unknown = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// OS/2 (default)
|
||||
/// </summary>
|
||||
OS2 = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Windows
|
||||
/// </summary>
|
||||
Windows = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// DOS 4.x
|
||||
/// </summary>
|
||||
DOS4x = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// Windows 386
|
||||
/// </summary>
|
||||
Windows386 = 0x04,
|
||||
}
|
||||
|
||||
public enum ResourceTableEntryType : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// "BTMP" - Bitmap
|
||||
/// </summary>
|
||||
BTMP = 0x504d5442,
|
||||
|
||||
/// <summary>
|
||||
/// "EMSG" - Error message string
|
||||
/// </summary>
|
||||
EMSG = 0x47534d45,
|
||||
|
||||
/// <summary>
|
||||
/// "FONT" - Fonts
|
||||
/// </summary>
|
||||
FONT = 0x544e4f46,
|
||||
}
|
||||
|
||||
public enum WordOrder : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// little-endian
|
||||
/// </summary>
|
||||
LE = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// big-endian
|
||||
/// </summary>
|
||||
/// <remarks>non-zero</remarks>
|
||||
BE = 0x01,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The `LINEAR` executable-file header contains information that the loader requires for
|
||||
/// segmented executable files. This information includes the linker version number, data
|
||||
/// specified by linker, data specified by resource compiler, tables of segment data, tables
|
||||
/// of resource data, and so on. The following illustrations shows the LE file header:
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
public sealed class Executable
|
||||
{
|
||||
/// <summary>
|
||||
/// MS-DOS executable stub
|
||||
/// </summary>
|
||||
public MSDOS.Executable? Stub { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Information block
|
||||
/// </summary>
|
||||
public InformationBlock? InformationBlock { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Object table
|
||||
/// </summary>
|
||||
public ObjectTableEntry[]? ObjectTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Object page map
|
||||
/// </summary>
|
||||
public ObjectPageMapEntry[]? ObjectPageMap { get; set; }
|
||||
|
||||
// TODO: Object iterate data map table (Undefined)
|
||||
|
||||
/// <summary>
|
||||
/// Resource table
|
||||
/// </summary>
|
||||
public ResourceTableEntry[]? ResourceTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Resident Name table
|
||||
/// </summary>
|
||||
public ResidentNamesTableEntry[]? ResidentNamesTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Entry table
|
||||
/// </summary>
|
||||
public EntryTableBundle[]? EntryTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Module format directives table (optional)
|
||||
/// </summary>
|
||||
public ModuleFormatDirectivesTableEntry[]? ModuleFormatDirectivesTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Verify record directive table (optional)
|
||||
/// </summary>
|
||||
public VerifyRecordDirectiveTableEntry[]? VerifyRecordDirectiveTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fix-up page table
|
||||
/// </summary>
|
||||
public FixupPageTableEntry[]? FixupPageTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fix-up record table
|
||||
/// </summary>
|
||||
public FixupRecordTableEntry[]? FixupRecordTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Import module name table
|
||||
/// </summary>
|
||||
public ImportModuleNameTableEntry[]? ImportModuleNameTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Import procedure name table
|
||||
/// </summary>
|
||||
public ImportModuleProcedureNameTableEntry[]? ImportModuleProcedureNameTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Per-Page checksum table
|
||||
/// </summary>
|
||||
public PerPageChecksumTableEntry[]? PerPageChecksumTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Non-Resident Name table
|
||||
/// </summary>
|
||||
public NonResidentNamesTableEntry[]? NonResidentNamesTable { get; set; }
|
||||
|
||||
// TODO: Non-resident directives data (Undefined)
|
||||
|
||||
/// <summary>
|
||||
/// Debug information
|
||||
/// </summary>
|
||||
public DebugInformation? DebugInformation { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The Fixup Page Table provides a simple mapping of a logical page number
|
||||
/// to an offset into the Fixup Record Table for that page.
|
||||
///
|
||||
/// This table is parallel to the Object Page Table, except that there is
|
||||
/// one additional entry in this table to indicate the end of the Fixup
|
||||
/// Record Table.
|
||||
///
|
||||
/// The fixup records are kept in order by logical page in the fixup record
|
||||
/// table. This allows the end of each page's fixup records is defined by the
|
||||
/// offset for the next logical page's fixup records. This last entry provides
|
||||
/// support of this mechanism for the last page in the fixup page table.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class FixupPageTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset for fixup record for this page. (1 to n)
|
||||
/// Offset to the end of the fixup records. (n + 1)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field specifies the offset, from the beginning of the fixup record
|
||||
/// table, to the first fixup record for this page. (1 to n)
|
||||
///
|
||||
/// This field specifies the offset following the last fixup record in the
|
||||
/// fixup record table. This is the last entry in the fixup page table. (n + 1)
|
||||
/// </remarks>
|
||||
public uint Offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The Fixup Record Table contains entries for all fixups in the linear EXE module.
|
||||
/// The fixup records for a logical page are grouped together and kept in sorted
|
||||
/// order by logical page number. The fixups for each page are further sorted such
|
||||
/// that all external fixups and internal selector/pointer fixups come before
|
||||
/// internal non-selector/non-pointer fixups. This allows the loader to ignore
|
||||
/// internal fixups if the loader is able to load all objects at the addresses
|
||||
/// specified in the object table.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
public sealed class FixupRecordTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Source type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The source type specifies the size and type of the fixup to be performed
|
||||
/// on the fixup source.
|
||||
/// </remarks>
|
||||
public FixupRecordSourceType SourceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Target Flags.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The target flags specify how the target information is interpreted.
|
||||
/// </remarks>
|
||||
public FixupRecordTargetFlags TargetFlags { get; set; }
|
||||
|
||||
#region Source List Flag
|
||||
|
||||
#region Set
|
||||
|
||||
/// <summary>
|
||||
/// Source offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field contains either an offset or a count depending on the Source
|
||||
/// List Flag. If the Source List Flag is set, a list of source offsets
|
||||
/// follows the additive field and this field contains the count of the
|
||||
/// entries in the source offset list. Otherwise, this is the single source
|
||||
/// offset for the fixup. Source offsets are relative to the beginning of
|
||||
/// the page where the fixup is to be made.
|
||||
///
|
||||
/// Note that for fixups that cross page boundaries, a separate fixup record
|
||||
/// is specified for each page. An offset is still used for the 2nd page but
|
||||
/// it now becomes a negative offset since the fixup originated on the
|
||||
/// preceding page. (For example, if only the last one byte of a 32-bit
|
||||
/// address is on the page to be fixed up, then the offset would have a value
|
||||
/// of -3.)
|
||||
/// </remarks>
|
||||
public ushort SourceOffset { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unset
|
||||
|
||||
/// <summary>
|
||||
/// Source offset list count.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field contains either an offset or a count depending on the Source
|
||||
/// List Flag. If the Source List Flag is set, a list of source offsets
|
||||
/// follows the additive field and this field contains the count of the
|
||||
/// entries in the source offset list. Otherwise, this is the single source
|
||||
/// offset for the fixup. Source offsets are relative to the beginning of
|
||||
/// the page where the fixup is to be made.
|
||||
///
|
||||
/// Note that for fixups that cross page boundaries, a separate fixup record
|
||||
/// is specified for each page. An offset is still used for the 2nd page but
|
||||
/// it now becomes a negative offset since the fixup originated on the
|
||||
/// preceding page. (For example, if only the last one byte of a 32-bit
|
||||
/// address is on the page to be fixed up, then the offset would have a value
|
||||
/// of -3.)
|
||||
/// </remarks>
|
||||
public byte SourceOffsetListCount { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region OBJECT / TRGOFF
|
||||
|
||||
#region 16-bit Object Number/Module Ordinal Flag
|
||||
|
||||
#region Set
|
||||
|
||||
/// <summary>
|
||||
/// Target object number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field is an index into the current module's Object Table to specify
|
||||
/// the target Object. It is a Byte value when the '16-bit Object Number/Module
|
||||
/// Ordinal Flag' bit in the target flags field is clear and a Word value when
|
||||
/// the bit is set.
|
||||
/// </remarks>
|
||||
public ushort TargetObjectNumberWORD { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unset
|
||||
|
||||
/// <summary>
|
||||
/// Target object number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field is an index into the current module's Object Table to specify
|
||||
/// the target Object. It is a Byte value when the '16-bit Object Number/Module
|
||||
/// Ordinal Flag' bit in the target flags field is clear and a Word value when
|
||||
/// the bit is set.
|
||||
/// </remarks>
|
||||
public byte TargetObjectNumberByte { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region 32-bit Target Offset Flag
|
||||
|
||||
#region Set
|
||||
|
||||
/// <summary>
|
||||
/// Target offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field is an offset into the specified target Object. It is not
|
||||
/// present when the Source Type specifies a 16-bit Selector fixup. It
|
||||
/// is a Word value when the '32-bit Target Offset Flag' bit in the target
|
||||
/// flags field is clear and a Dword value when the bit is set.
|
||||
/// </remarks>
|
||||
public uint TargetOffsetDWORD { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unset
|
||||
|
||||
/// <summary>
|
||||
/// Target offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field is an offset into the specified target Object. It is not
|
||||
/// present when the Source Type specifies a 16-bit Selector fixup. It
|
||||
/// is a Word value when the '32-bit Target Offset Flag' bit in the target
|
||||
/// flags field is clear and a Dword value when the bit is set.
|
||||
/// </remarks>
|
||||
public ushort TargetOffsetWORD { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region 16-bit Object Number/Module Ordinal Flag [Incompatible with OBJECT / TRGOFF]
|
||||
|
||||
#region Set
|
||||
|
||||
/// <summary>
|
||||
/// Ordinal index into the Import Module Name Table.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is an ordered index in to the Import Module Name Table for
|
||||
/// the module containing the procedure entry point. It is a Byte value
|
||||
/// when the '16-bit Object Number/Module Ordinal' Flag bit in the target
|
||||
/// flags field is clear and a Word value when the bit is set. The loader
|
||||
/// creates a table of pointers with each pointer in the table corresponds
|
||||
/// to the modules named in the Import Module Name Table. This value is used
|
||||
/// by the loader to index into this table created by the loader to locate
|
||||
/// the referenced module.
|
||||
/// </remarks>
|
||||
public ushort OrdinalIndexImportModuleNameTableWORD { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unset
|
||||
|
||||
/// <summary>
|
||||
/// Ordinal index into the Import Module Name Table.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is an ordered index in to the Import Module Name Table for
|
||||
/// the module containing the procedure entry point. It is a Byte value
|
||||
/// when the '16-bit Object Number/Module Ordinal' Flag bit in the target
|
||||
/// flags field is clear and a Word value when the bit is set. The loader
|
||||
/// creates a table of pointers with each pointer in the table corresponds
|
||||
/// to the modules named in the Import Module Name Table. This value is used
|
||||
/// by the loader to index into this table created by the loader to locate
|
||||
/// the referenced module.
|
||||
/// </remarks>
|
||||
public byte OrdinalIndexImportModuleNameTableByte { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region MOD ORD# / PROCEDURE NAME OFFSET / ADDITIVE
|
||||
|
||||
#region 32-bit Target Offset Flag
|
||||
|
||||
#region Set
|
||||
|
||||
/// <summary>
|
||||
/// Offset into the Import Procedure Name Table.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field is an offset into the Import Procedure Name Table. It is
|
||||
/// a Word value when the '32-bit Target Offset Flag' bit in the target
|
||||
/// flags field is clear and a Dword value when the bit is set.
|
||||
/// </remarks>
|
||||
public uint OffsetImportProcedureNameTableDWORD { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unset
|
||||
|
||||
/// <summary>
|
||||
/// Offset into the Import Procedure Name Table.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field is an offset into the Import Procedure Name Table. It is
|
||||
/// a Word value when the '32-bit Target Offset Flag' bit in the target
|
||||
/// flags field is clear and a Dword value when the bit is set.
|
||||
/// </remarks>
|
||||
public ushort OffsetImportProcedureNameTableWORD { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region MOD ORD# / IMPORT ORD / ADDITIVE
|
||||
|
||||
#region 8-bit Ordinal Flag
|
||||
|
||||
#region Set
|
||||
|
||||
/// <summary>
|
||||
/// Imported ordinal number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the imported procedure's ordinal number. It is a Byte value when the
|
||||
/// '8-bit Ordinal' bit in the target flags field is set. Otherwise it is a Word value
|
||||
/// when the '32-bit Target Offset Flag' bit in the target flags field is clear and a
|
||||
/// Dword value when the bit is set.
|
||||
/// </remarks>
|
||||
public byte ImportedOrdinalNumberByte { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unset
|
||||
|
||||
#region 32-bit Target Offset Flag
|
||||
|
||||
#region Set
|
||||
|
||||
/// <summary>
|
||||
/// Imported ordinal number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the imported procedure's ordinal number. It is a Byte value when the
|
||||
/// '8-bit Ordinal' bit in the target flags field is set. Otherwise it is a Word value
|
||||
/// when the '32-bit Target Offset Flag' bit in the target flags field is clear and a
|
||||
/// Dword value when the bit is set.
|
||||
/// </remarks>
|
||||
public uint ImportedOrdinalNumberDWORD { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unset
|
||||
|
||||
/// <summary>
|
||||
/// Imported ordinal number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the imported procedure's ordinal number. It is a Byte value when the
|
||||
/// '8-bit Ordinal' bit in the target flags field is set. Otherwise it is a Word value
|
||||
/// when the '32-bit Target Offset Flag' bit in the target flags field is clear and a
|
||||
/// Dword value when the bit is set.
|
||||
/// </remarks>
|
||||
public uint ImportedOrdinalNumberWORD { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Additive Fixup Flag [Incompatible with OBJECT / TRGOFF]
|
||||
|
||||
#region Set
|
||||
|
||||
#region 32-bit Additive Fixup Flag
|
||||
|
||||
#region Set
|
||||
|
||||
/// <summary>
|
||||
/// Additive fixup value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field exists in the fixup record only when the 'Additive Fixup Flag'
|
||||
/// bit in the target flags field is set. When the 'Additive Fixup Flag' is
|
||||
/// clear the fixup record does not contain this field and is immediately
|
||||
/// followed by the next fixup record (or by the source offset list for this
|
||||
/// fixup record).
|
||||
///
|
||||
/// This value is added to the address derived from the target entry point.
|
||||
/// This field is a Word value when the '32-bit Additive Flag' bit in the
|
||||
/// target flags field is clear and a Dword value when the bit is set.
|
||||
/// </remarks>
|
||||
public uint AdditiveFixupValueDWORD { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unset
|
||||
|
||||
/// <summary>
|
||||
/// Additive fixup value.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field exists in the fixup record only when the 'Additive Fixup Flag'
|
||||
/// bit in the target flags field is set. When the 'Additive Fixup Flag' is
|
||||
/// clear the fixup record does not contain this field and is immediately
|
||||
/// followed by the next fixup record (or by the source offset list for this
|
||||
/// fixup record).
|
||||
///
|
||||
/// This value is added to the address derived from the target entry point.
|
||||
/// This field is a Word value when the '32-bit Additive Flag' bit in the
|
||||
/// target flags field is clear and a Dword value when the bit is set.
|
||||
/// </remarks>
|
||||
public ushort AdditiveFixupValueWORD { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region SCROFFn
|
||||
|
||||
/// <summary>
|
||||
/// Source offset list.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This list is present if the Source List Flag is set in the Target Flags field.
|
||||
/// The number of entries in the source offset list is defined in the SRCOFF/CNT
|
||||
/// field. The source offsets are relative to the beginning of the page where the
|
||||
/// fixups are to be made.
|
||||
/// </remarks>
|
||||
public ushort[]? SourceOffsetList { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The import module name table defines the module name strings imported through
|
||||
/// dynamic link references. These strings are referenced through the imported
|
||||
/// relocation fixups.
|
||||
///
|
||||
/// To determine the length of the import module name table subtract the import
|
||||
/// module name table offset from the import procedure name table offset. These
|
||||
/// values are located in the linear EXE header. The end of the import module
|
||||
/// name table is not terminated by a special character, it is followed directly
|
||||
/// by the import procedure name table.
|
||||
///
|
||||
/// The strings are CASE SENSITIVE and NOT NULL TERMINATED.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
public sealed class ImportModuleNameTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// String Length.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This defines the length of the string in bytes. The length of each
|
||||
/// ascii name string is limited to 127 characters.
|
||||
/// </remarks>
|
||||
public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
|
||||
|
||||
/// <summary>
|
||||
/// ASCII String.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a variable length string with it's length defined in bytes by
|
||||
/// the LEN field. The string is case sensitive and is not null terminated.
|
||||
/// </remarks>
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The import procedure name table defines the procedure name strings imported
|
||||
/// by this module through dynamic link references. These strings are referenced
|
||||
/// through the imported relocation fixups.
|
||||
///
|
||||
/// To determine the length of the import procedure name table add the fixup
|
||||
/// section size to the fixup page table offset, this computes the offset to
|
||||
/// the end of the fixup section, then subtract the import procedure name table
|
||||
/// offset. These values are located in the linear EXE header. The import
|
||||
/// procedure name table is followed by the data pages section. Since the data
|
||||
/// pages section is aligned on a 'page size' boundary, padded space may exist
|
||||
/// between the last import name string and the first page in the data pages
|
||||
/// section. If this padded space exists it will be zero filled.
|
||||
///
|
||||
/// The strings are CASE SENSITIVE and NOT NULL TERMINATED.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
public sealed class ImportModuleProcedureNameTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// String Length.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This defines the length of the string in bytes. The length of each
|
||||
/// ascii name string is limited to 127 characters.
|
||||
///
|
||||
/// The high bit in the LEN field (bit 7) is defined as an Overload bit.
|
||||
/// This bit signifies that additional information is contained in the
|
||||
/// linear EXE module and will be used in the future for parameter type
|
||||
/// checking.
|
||||
/// </remarks>
|
||||
public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
|
||||
|
||||
/// <summary>
|
||||
/// ASCII String.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a variable length string with it's length defined in bytes by
|
||||
/// the LEN field. The string is case sensitive and is not null terminated.
|
||||
/// </remarks>
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,432 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The `information block` in the LE header contains the linker version number,
|
||||
/// length of various tables that further describe the executable file, the
|
||||
/// offsets from the beginning of the header to the beginning of these tables,
|
||||
/// the heap and stack sizes, and so on. The following list summarizes the
|
||||
/// contents of the header `information block` (the locations are relative to
|
||||
/// the beginning of the block):
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
public sealed class InformationBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the signature word
|
||||
/// 'LE' (4Ch 45H)
|
||||
/// 'LX' (4Ch 58H)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The signature word is used by the loader to identify the EXE
|
||||
/// file as a valid 32-bit Linear Executable Module Format.
|
||||
/// </remarks>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
|
||||
public string? Signature;
|
||||
|
||||
/// <summary>
|
||||
/// Byte Ordering.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This byte specifies the byte ordering for the linear EXE format.
|
||||
/// </remarks>
|
||||
[MarshalAs(UnmanagedType.U1)]
|
||||
public ByteOrder ByteOrder;
|
||||
|
||||
/// <summary>
|
||||
/// Word Ordering.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This byte specifies the Word ordering for the linear EXE format.
|
||||
/// </remarks>
|
||||
[MarshalAs(UnmanagedType.U1)]
|
||||
public WordOrder WordOrder;
|
||||
|
||||
/// <summary>
|
||||
/// Linear EXE Format Level.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Linear EXE Format Level is set to 0 for the initial version of the
|
||||
/// 32-bit linear EXE format. Each incompatible change to the linear EXE
|
||||
/// format must increment this value. This allows the system to recognized
|
||||
/// future EXE file versions so that an appropriate error message may be
|
||||
/// displayed if an attempt is made to load them.
|
||||
/// </remarks>
|
||||
public uint ExecutableFormatLevel;
|
||||
|
||||
/// <summary>
|
||||
/// Module CPU Type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field specifies the type of CPU required by this module to run.
|
||||
/// </remarks>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public CPUType CPUType;
|
||||
|
||||
/// <summary>
|
||||
/// Module OS Type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field specifies the type of Operating system required to run this module.
|
||||
/// </remarks>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public OperatingSystem ModuleOS;
|
||||
|
||||
/// <summary>
|
||||
/// Module version
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is useful for differentiating between revisions of dynamic linked modules.
|
||||
/// This value is specified at link time by the user.
|
||||
/// </remarks>
|
||||
public uint ModuleVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Module type flags
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U4)]
|
||||
public ModuleFlags ModuleTypeFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Number of pages in module.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field specifies the number of pages physically contained in this module.
|
||||
/// In other words, pages containing either enumerated or iterated data, or
|
||||
/// zero-fill pages that have relocations, not invalid or zero-fill pages implied
|
||||
/// by the Virtual Size in the Object Table being larger than the number of pages
|
||||
/// actually in the linear EXE file. These pages are contained in the 'preload
|
||||
/// pages', 'demand load pages' and 'iterated data pages' sections of the linear
|
||||
/// EXE module. This is used to determine the size of the page information tables
|
||||
/// in the linear EXE module.
|
||||
/// </remarks>
|
||||
public uint ModuleNumberPages;
|
||||
|
||||
/// <summary>
|
||||
/// The Object number to which the Entry Address is relative.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This specifies the object to which the Entry Address is relative. This must be
|
||||
/// a nonzero value for a program module to be correctly loaded. A zero value for
|
||||
/// a library module indicates that no library entry routine exists. If this value
|
||||
/// is zero, then both the Per-process Library Initialization bit and the Per-process
|
||||
/// Library Termination bit must be clear in the module flags, or else the loader
|
||||
/// will fail to load the module. Further, if the Per-process Library Termination bit
|
||||
/// is set, then the object to which this field refers must be a 32-bit object (i.e.,
|
||||
/// the Big/Default bit must be set in the object flags; see below).
|
||||
/// </remarks>
|
||||
public uint InitialObjectCS;
|
||||
|
||||
/// <summary>
|
||||
/// Entry Address of module.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Entry Address is the starting address for program modules and the library
|
||||
/// initialization and Library termination address for library modules.
|
||||
/// </remarks>
|
||||
public uint InitialEIP;
|
||||
|
||||
/// <summary>
|
||||
/// The Object number to which the ESP is relative.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This specifies the object to which the starting ESP is relative. This must be a
|
||||
/// nonzero value for a program module to be correctly loaded. This field is ignored
|
||||
/// for a library module.
|
||||
/// </remarks>
|
||||
public uint InitialObjectSS;
|
||||
|
||||
/// <summary>
|
||||
/// Starting stack address of module.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The ESP defines the starting stack pointer address for program modules. A zero
|
||||
/// value in this field indicates that the stack pointer is to be initialized to the
|
||||
/// highest address/offset in the object. This field is ignored for a library module.
|
||||
/// </remarks>
|
||||
public uint InitialESP;
|
||||
|
||||
/// <summary>
|
||||
/// The size of one page for this system.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field specifies the page size used by the linear EXE format and the system.
|
||||
/// For the initial version of this linear EXE format the page size is 4Kbytes.
|
||||
/// (The 4K page size is specified by a value of 4096 in this field.)
|
||||
/// </remarks>
|
||||
public uint MemoryPageSize;
|
||||
|
||||
/// <summary>
|
||||
/// The shift left bits for page offsets.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field gives the number of bit positions to shift left when interpreting
|
||||
/// the Object Page Table entries' page offset field. This determines the alignment
|
||||
/// of the page information in the file. For example, a value of 4 in this field
|
||||
/// would align all pages in the Data Pages and Iterated Pages sections on 16 byte
|
||||
/// (paragraph) boundaries. A Page Offset Shift of 9 would align all pages on a
|
||||
/// 512 byte (disk sector) basis. The default value for this field is 12 (decimal),
|
||||
/// which give a 4096 byte alignment. All other offsets are byte aligned.
|
||||
/// </remarks>
|
||||
public uint BytesOnLastPage;
|
||||
|
||||
/// <summary>
|
||||
/// Total size of the fixup information in bytes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This includes the following 4 tables:
|
||||
/// - Fixup Page Table
|
||||
/// - Fixup Record Table
|
||||
/// - Import Module name Table
|
||||
/// - Import Procedure Name Table
|
||||
/// </remarks>
|
||||
public uint FixupSectionSize;
|
||||
|
||||
/// <summary>
|
||||
/// Checksum for fixup information.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a cryptographic checksum covering all of the fixup information. The
|
||||
/// checksum for the fixup information is kept separate because the fixup data is
|
||||
/// not always loaded into main memory with the 'loader section'. If the checksum
|
||||
/// feature is not implemented, then the linker will set these fields to zero.
|
||||
/// </remarks>
|
||||
public uint FixupSectionChecksum;
|
||||
|
||||
/// <summary>
|
||||
/// Size of memory resident tables.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the total size in bytes of the tables required to be memory resident
|
||||
/// for the module, while the module is in use. This total size includes all
|
||||
/// tables from the Object Table down to and including the Per-Page Checksum Table.
|
||||
/// </remarks>
|
||||
public uint LoaderSectionSize;
|
||||
|
||||
/// <summary>
|
||||
/// Checksum for loader section.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a cryptographic checksum covering all of the loader section information.
|
||||
/// If the checksum feature is not implemented, then the linker will set these fields
|
||||
/// to zero.
|
||||
/// </remarks>
|
||||
public uint LoaderSectionChecksum;
|
||||
|
||||
/// <summary>
|
||||
/// Object Table offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint ObjectTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Object Table Count.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This defines the number of entries in Object Table.
|
||||
/// </remarks>
|
||||
public uint ObjectTableCount;
|
||||
|
||||
/// <summary>
|
||||
/// Object Page Table offset
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint ObjectPageMapOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Object Iterated Pages offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint ObjectIterateDataMapOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Resource Table offset
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint ResourceTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Number of entries in Resource Table.
|
||||
/// </summary>
|
||||
public uint ResourceTableCount;
|
||||
|
||||
/// <summary>
|
||||
/// Resident Name Table offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint ResidentNamesTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Entry Table offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint EntryTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Module Format Directives Table offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint ModuleDirectivesTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Number of Module Format Directives in the Table.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field specifies the number of entries in the
|
||||
/// Module Format Directives Table.
|
||||
/// </remarks>
|
||||
public uint ModuleDirectivesCount;
|
||||
|
||||
/// <summary>
|
||||
/// Fixup Page Table offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint FixupPageTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Fixup Record Table offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint FixupRecordTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Import Module Name Table offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint ImportedModulesNameTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// The number of entries in the Import Module Name Table.
|
||||
/// </summary>
|
||||
public uint ImportedModulesCount;
|
||||
|
||||
/// <summary>
|
||||
/// Import Procedure Name Table offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint ImportProcedureNameTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Per-page Checksum Table offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint PerPageChecksumTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Data Pages Offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the EXE file.
|
||||
/// </remarks>
|
||||
public uint DataPagesOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Number of Preload pages for this module.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that OS/2 2.0 does not respect the preload of pages as specified
|
||||
/// in the executable file for performance reasons.
|
||||
/// </remarks>
|
||||
public uint PreloadPageCount;
|
||||
|
||||
/// <summary>
|
||||
/// Non-Resident Name Table offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the EXE file.
|
||||
/// </remarks>
|
||||
public uint NonResidentNamesTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Number of bytes in the Non-resident name table.
|
||||
/// </summary>
|
||||
public uint NonResidentNamesTableLength;
|
||||
|
||||
/// <summary>
|
||||
/// Non-Resident Name Table Checksum.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a cryptographic checksum of the Non-Resident Name Table.
|
||||
/// </remarks>
|
||||
public uint NonResidentNamesTableChecksum;
|
||||
|
||||
/// <summary>
|
||||
/// The Auto Data Segment Object number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the object number for the Auto Data Segment used by 16-bit modules.
|
||||
/// This field is supported for 16-bit compatibility only and is not used by
|
||||
/// 32-bit modules.
|
||||
/// </remarks>
|
||||
public uint AutomaticDataObject;
|
||||
|
||||
/// <summary>
|
||||
/// Debug Information offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This offset is relative to the beginning of the linear EXE header.
|
||||
/// </remarks>
|
||||
public uint DebugInformationOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Debug Information length.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The length of the debug information in bytes.
|
||||
/// </remarks>
|
||||
public uint DebugInformationLength;
|
||||
|
||||
/// <summary>
|
||||
/// Instance pages in preload section.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The number of instance data pages found in the preload section.
|
||||
/// </remarks>
|
||||
public uint PreloadInstancePagesNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Instance pages in demand section.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The number of instance data pages found in the demand section.
|
||||
/// </remarks>
|
||||
public uint DemandInstancePagesNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Heap size added to the Auto DS Object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The heap size is the number of bytes added to the Auto Data Segment
|
||||
/// by the loader. This field is supported for 16-bit compatibility only and
|
||||
/// is not used by 32-bit modules.
|
||||
/// </remarks>
|
||||
public uint ExtraHeapAllocation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The Module Format Directives Table is an optional table that allows additional
|
||||
/// options to be specified. It also allows for the extension of the linear EXE
|
||||
/// format by allowing additional tables of information to be added to the linear
|
||||
/// EXE module without affecting the format of the linear EXE header. Likewise,
|
||||
/// module format directives provide a place in the linear EXE module for
|
||||
/// 'temporary tables' of information, such as incremental linking information
|
||||
/// and statistic information gathered on the module. When there are no module
|
||||
/// format directives for a linear EXE module, the fields in the linear EXE header
|
||||
/// referencing the module format directives table are zero.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class ModuleFormatDirectivesTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Directive number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The directive number specifies the type of directive defined. This can be
|
||||
/// used to determine the format of the information in the directive data.
|
||||
/// </remarks>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public DirectiveNumber DirectiveNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Directive data length.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This specifies the length in byte of the directive data for this directive number.
|
||||
/// </remarks>
|
||||
public ushort DirectiveDataLength;
|
||||
|
||||
/// <summary>
|
||||
/// Directive data offset.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the offset to the directive data for this directive number. It is relative
|
||||
/// to beginning of linear EXE header for a resident table, and relative to the
|
||||
/// beginning of the EXE file for non-resident tables.
|
||||
/// </remarks>
|
||||
public uint DirectiveDataOffset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The resident and non-resident name tables define the ASCII names and ordinal
|
||||
/// numbers for exported entries in the module. In addition the first entry in
|
||||
/// the resident name table contains the module name. These tables are used to
|
||||
/// translate a procedure name string into an ordinal number by searching for a
|
||||
/// matching name string. The ordinal number is used to locate the entry point
|
||||
/// information in the entry table.
|
||||
///
|
||||
/// The resident name table is kept resident in system memory while the module is
|
||||
/// loaded.It is intended to contain the exported entry point names that are
|
||||
/// frequently dynamically linked to by name.Non-resident names are not kept in
|
||||
/// memory and are read from the EXE file when a dynamic link reference is made.
|
||||
/// Exported entry point names that are infrequently dynamically linked to by name
|
||||
/// or are commonly referenced by ordinal number should be placed in the
|
||||
/// non-resident name table.The trade off made for references by name is performance
|
||||
/// vs memory usage.
|
||||
///
|
||||
/// Import references by name require these tables to be searched to obtain the entry
|
||||
/// point ordinal number.Import references by ordinal number provide the fastest
|
||||
/// lookup since the search of these tables is not required.
|
||||
///
|
||||
/// The strings are CASE SENSITIVE and are NOT NULL TERMINATED.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class NonResidentNamesTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// String Length.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This defines the length of the string in bytes. A zero length indicates there are
|
||||
/// no more entries in table. The length of each ascii name string is limited to 127
|
||||
/// characters.
|
||||
///
|
||||
/// The high bit in the LEN field (bit 7) is defined as an Overload bit. This bit
|
||||
/// signifies that additional information is contained in the linear EXE module and
|
||||
/// will be used in the future for parameter type checking.
|
||||
/// </remarks>
|
||||
public byte Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ASCII String.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a variable length string with it's length defined in bytes by the LEN field.
|
||||
/// The string is case case sensitive and is not null terminated.
|
||||
/// </remarks>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ordinal number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The ordinal number in an ordered index into the entry table for this entry point.
|
||||
/// </remarks>
|
||||
public ushort OrdinalNumber { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The Object page table provides information about a logical page in an object.
|
||||
/// A logical page may be an enumerated page, a pseudo page or an iterated page.
|
||||
/// The structure of the object page table in conjunction with the structure of
|
||||
/// the object table allows for efficient access of a page when a page fault occurs,
|
||||
/// while still allowing the physical page data to be located in the preload page,
|
||||
/// demand load page or iterated data page sections in the linear EXE module. The
|
||||
/// logical page entries in the Object Page Table are numbered starting from one.
|
||||
/// The Object Page Table is parallel to the Fixup Page Table as they are both
|
||||
/// indexed by the logical page number.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class ObjectPageMapEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset to the page data in the EXE file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field, when bit shifted left by the PAGE OFFSET SHIFT from the module
|
||||
/// header, specifies the offset from the beginning of the Preload Page section
|
||||
/// of the physical page data in the EXE file that corresponds to this logical
|
||||
/// page entry. The page data may reside in the Preload Pages, Demand Load Pages
|
||||
/// or the Iterated Data Pages sections.
|
||||
///
|
||||
/// If the FLAGS field specifies that this is a zero-Filled page then the PAGE
|
||||
/// DATA OFFSET field will contain a 0.
|
||||
///
|
||||
/// If the logical page is specified as an iterated data page, as indicated by
|
||||
/// the FLAGS field, then this field specifies the offset into the Iterated Data
|
||||
/// Pages section.
|
||||
///
|
||||
/// The logical page number (Object Page Table index), is used to index the Fixup
|
||||
/// Page Table to find any fixups associated with the logical page.
|
||||
/// </remarks>
|
||||
public uint PageDataOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Number of bytes of data for this page.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field specifies the actual number of bytes that represent the page in the
|
||||
/// file. If the PAGE SIZE field from the module header is greater than the value
|
||||
/// of this field and the FLAGS field indicates a Legal Physical Page, the remaining
|
||||
/// bytes are to be filled with zeros. If the FLAGS field indicates an Iterated Data
|
||||
/// Page, the iterated data records will completely fill out the remainder.
|
||||
/// </remarks>
|
||||
public ushort DataSize;
|
||||
|
||||
/// <summary>
|
||||
/// Attributes specifying characteristics of this logical page.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public ObjectPageFlags Flags;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The object table contains information that describes each segment in
|
||||
/// an executable file. This information includes segment length, segment
|
||||
/// type, and segment-relocation data. The following list summarizes the
|
||||
/// values found in in the segment table (the locations are relative to
|
||||
/// the beginning of each entry):
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Entries in the Object Table are numbered starting from one.
|
||||
/// </remarks>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class ObjectTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Virtual memory size.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the size of the object that will be allocated when the object
|
||||
/// is loaded. The object's virtual size (rounded up to the page size value)
|
||||
/// must be greater than or equal to the total size of the pages in the EXE
|
||||
/// file for the object. This memory size must also be large enough to
|
||||
/// contain all of the iterated data and uninitialized data in the EXE file.
|
||||
/// </remarks>
|
||||
public uint VirtualSegmentSize;
|
||||
|
||||
/// <summary>
|
||||
/// Relocation Base Address.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The relocation base address the object is currently relocated to. If the
|
||||
/// internal relocation fixups for the module have been removed, this is the
|
||||
/// address the object will be allocated at by the loader.
|
||||
/// </remarks>
|
||||
public uint RelocationBaseAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Flag bits for the object.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public ObjectFlags ObjectFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Object Page Table Index.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This specifies the number of the first object page table entry for this object.
|
||||
/// The object page table specifies where in the EXE file a page can be found for
|
||||
/// a given object and specifies per-page attributes.
|
||||
///
|
||||
/// The object table entries are ordered by logical page in the object table. In
|
||||
/// other words the object table entries are sorted based on the object page table
|
||||
/// index value.
|
||||
/// </remarks>
|
||||
public uint PageTableIndex;
|
||||
|
||||
/// <summary>
|
||||
/// # of object page table entries for this object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Any logical pages at the end of an object that do not have an entry in the object
|
||||
/// page table associated with them are handled as zero filled or invalid pages by
|
||||
/// the loader.
|
||||
///
|
||||
/// When the last logical pages of an object are not specified with an object page
|
||||
/// table entry, they are treated as either zero filled pages or invalid pages based
|
||||
/// on the last entry in the object page table for that object. If the last entry
|
||||
/// was neither a zero filled or invalid page, then the additional pages are treated
|
||||
/// as zero filled pages.
|
||||
/// </remarks>
|
||||
public uint PageTableEntries;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved for future use. Must be set to zero.
|
||||
/// </summary>
|
||||
public uint Reserved;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The Per-Page Checksum table provides space for a cryptographic checksum for
|
||||
/// each physical page in the EXE file.
|
||||
///
|
||||
/// The checksum table is arranged such that the first entry in the table corresponds
|
||||
/// to the first logical page of code/data in the EXE file (usually a preload page)
|
||||
/// and the last entry corresponds to the last logical page in the EXE file (usually
|
||||
/// a iterated data page).
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class PerPageChecksumTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Cryptographic checksum.
|
||||
/// </summary>
|
||||
public uint Checksum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The resident and non-resident name tables define the ASCII names and ordinal
|
||||
/// numbers for exported entries in the module. In addition the first entry in
|
||||
/// the resident name table contains the module name. These tables are used to
|
||||
/// translate a procedure name string into an ordinal number by searching for a
|
||||
/// matching name string. The ordinal number is used to locate the entry point
|
||||
/// information in the entry table.
|
||||
///
|
||||
/// The resident name table is kept resident in system memory while the module is
|
||||
/// loaded. It is intended to contain the exported entry point names that are
|
||||
/// frequently dynamically linked to by name. Non-resident names are not kept in
|
||||
/// memory and are read from the EXE file when a dynamic link reference is made.
|
||||
/// Exported entry point names that are infrequently dynamically linked to by name
|
||||
/// or are commonly referenced by ordinal number should be placed in the
|
||||
/// non-resident name table. The trade off made for references by name is performance
|
||||
/// vs memory usage.
|
||||
///
|
||||
/// Import references by name require these tables to be searched to obtain the entry
|
||||
/// point ordinal number.Import references by ordinal number provide the fastest
|
||||
/// lookup since the search of these tables is not required.
|
||||
///
|
||||
/// The strings are CASE SENSITIVE and are NOT NULL TERMINATED.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
public sealed class ResidentNamesTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// String Length.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This defines the length of the string in bytes. A zero length indicates there are
|
||||
/// no more entries in table. The length of each ascii name string is limited to 127
|
||||
/// characters.
|
||||
///
|
||||
/// The high bit in the LEN field (bit 7) is defined as an Overload bit. This bit
|
||||
/// signifies that additional information is contained in the linear EXE module and
|
||||
/// will be used in the future for parameter type checking.
|
||||
/// </remarks>
|
||||
public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
|
||||
|
||||
/// <summary>
|
||||
/// ASCII String.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a variable length string with it's length defined in bytes by the LEN field.
|
||||
/// The string is case case sensitive and is not null terminated.
|
||||
/// </remarks>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ordinal number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The ordinal number in an ordered index into the entry table for this entry point.
|
||||
/// </remarks>
|
||||
public ushort OrdinalNumber { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The resource table is an array of resource table entries. Each resource table
|
||||
/// entry contains a type ID and name ID. These entries are used to locate resource
|
||||
/// objects contained in the Object table. The number of entries in the resource
|
||||
/// table is defined by the Resource Table Count located in the linear EXE header.
|
||||
/// More than one resource may be contained within a single object. Resource table
|
||||
/// entries are in a sorted order, (ascending, by Resource Name ID within the
|
||||
/// Resource Type ID). This allows the DosGetResource API function to use a binary
|
||||
/// search when looking up a resource in a 32-bit module instead of the linear search
|
||||
/// being used in the current 16-bit module.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class ResourceTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Resource type ID.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U4)]
|
||||
public ResourceTableEntryType TypeID;
|
||||
|
||||
/// <summary>
|
||||
/// An ID used as a name for the resource when referred to.
|
||||
/// </summary>
|
||||
public ushort NameID;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes the resource consists of.
|
||||
/// </summary>
|
||||
public uint ResourceSize;
|
||||
|
||||
/// <summary>
|
||||
/// The number of the object which contains the resource.
|
||||
/// </summary>
|
||||
public ushort ObjectNumber;
|
||||
|
||||
/// <summary>
|
||||
/// The offset within the specified object where the resource begins.
|
||||
/// </summary>
|
||||
public uint Offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.LinearExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The Verify Record Directive Table is an optional table. It maintains a record
|
||||
/// of the pages in the EXE file that have been fixed up and written back to the
|
||||
/// original linear EXE module, along with the module dependencies used to perform
|
||||
/// these fixups. This table provides an efficient means for verifying the virtual
|
||||
/// addresses required for the fixed up pages when the module is loaded.
|
||||
/// </summary>
|
||||
/// <see href="https://faydoc.tripod.com/formats/exe-LE.htm"/>
|
||||
/// <see href="http://www.edm2.com/index.php/LX_-_Linear_eXecutable_Module_Format_Description"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class VerifyRecordDirectiveTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of module dependencies.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field specifies how many entries there are in the verify record
|
||||
/// directive table. This is equal to the number of modules referenced by
|
||||
/// this module.
|
||||
/// </remarks>
|
||||
public ushort EntryCount;
|
||||
|
||||
/// <summary>
|
||||
/// Ordinal index into the Import Module Name Table.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This value is an ordered index in to the Import Module Name Table for
|
||||
/// the referenced module.
|
||||
/// </remarks>
|
||||
public ushort OrdinalIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Module Version.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the version of the referenced module that the fixups were
|
||||
/// originally performed.This is used to insure the same version of the
|
||||
/// referenced module is loaded that was fixed up in this module and
|
||||
/// therefore the fixups are still correct. This requires the version
|
||||
/// number in a module to be incremented anytime the entry point offsets
|
||||
/// change.
|
||||
/// </remarks>
|
||||
public ushort Version;
|
||||
|
||||
/// <summary>
|
||||
/// Module # of Object Entries.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field is used to identify the number of object verify entries
|
||||
/// that follow for the referenced module.
|
||||
/// </remarks>
|
||||
public ushort ObjectEntriesCount;
|
||||
|
||||
/// <summary>
|
||||
/// Object # in Module.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field specifies the object number in the referenced module that
|
||||
/// is being verified.
|
||||
/// </remarks>
|
||||
public ushort ObjectNumberInModule;
|
||||
|
||||
/// <summary>
|
||||
/// Object load base address.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the address that the object was loaded at when the fixups were
|
||||
/// performed.
|
||||
/// </remarks>
|
||||
public ushort ObjectLoadBaseAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Object virtual address size.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This field specifies the total amount of virtual memory required for
|
||||
/// this object.
|
||||
/// </remarks>
|
||||
public ushort ObjectVirtualAddressSize;
|
||||
}
|
||||
}
|
||||
11
SabreTools.Serialization/Models/MSDOS/Constants.cs
Normal file
11
SabreTools.Serialization/Models/MSDOS/Constants.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace SabreTools.Serialization.Models.MSDOS
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly byte[] SignatureBytes = [0x4d, 0x5a];
|
||||
|
||||
public const string SignatureString = "MZ";
|
||||
|
||||
public const ushort SignatureUInt16 = 0x5a4d;
|
||||
}
|
||||
}
|
||||
29
SabreTools.Serialization/Models/MSDOS/Executable.cs
Normal file
29
SabreTools.Serialization/Models/MSDOS/Executable.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace SabreTools.Serialization.Models.MSDOS
|
||||
{
|
||||
/// <summary>
|
||||
/// The MS-DOS EXE format, also known as MZ after its signature (the initials of Microsoft engineer Mark Zbykowski),
|
||||
/// was introduced with MS-DOS 2.0 (version 1.0 only sported the simple COM format). It is designed as a relocatable
|
||||
/// executable running under real mode. As such, only DOS and Windows 9x can use this format natively, but there are
|
||||
/// several free DOS emulators (e.g., DOSBox) that support it and that run under various operating systems (e.g.,
|
||||
/// Linux, Amiga, Windows NT, etc.). Although they can exist on their own, MZ executables are embedded in all NE, LE,
|
||||
/// and PE executables, usually as stubs so that when they are ran under DOS, they display a warning.
|
||||
/// </summary>
|
||||
/// <see href="https://wiki.osdev.org/MZ"/>
|
||||
public sealed class Executable
|
||||
{
|
||||
/// <summary>
|
||||
/// MS-DOS executable header
|
||||
/// </summary>
|
||||
public ExecutableHeader? Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// After loading the executable into memory, the program loader goes through
|
||||
/// every entry in relocation table. For each relocation entry, the loader
|
||||
/// adds the start segment address into word value pointed to by the
|
||||
/// segment:offset pair. So, for example, a relocation entry 0001:001A will
|
||||
/// make the loader add start segment address to the value at offset
|
||||
/// 1*0x10+0x1A=0x2A within the program data.
|
||||
/// </summary>
|
||||
public RelocationEntry[]? RelocationTable { get; set; }
|
||||
}
|
||||
}
|
||||
133
SabreTools.Serialization/Models/MSDOS/ExecutableHeader.cs
Normal file
133
SabreTools.Serialization/Models/MSDOS/ExecutableHeader.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.MSDOS
|
||||
{
|
||||
/// <summary>
|
||||
/// MZ executables only consists of 2 structures: the header and the relocation table.
|
||||
/// The header, which is followed by the program image, looks like this.
|
||||
/// </summary>
|
||||
/// <see href="https://wiki.osdev.org/MZ"/>
|
||||
/// <see href="http://www.pinvoke.net/default.aspx/Structures.IMAGE_DOS_HEADER"/>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
public sealed class ExecutableHeader
|
||||
{
|
||||
#region Standard Fields
|
||||
|
||||
/// <summary>
|
||||
/// 0x5A4D (ASCII for 'M' and 'Z')
|
||||
/// </summary>
|
||||
/// <remarks>15 bytes</remarks>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
|
||||
public string? Magic;
|
||||
|
||||
/// <summary>
|
||||
/// Number of bytes in the last page.
|
||||
/// </summary>
|
||||
public ushort LastPageBytes;
|
||||
|
||||
/// <summary>
|
||||
/// Number of whole/partial pages.
|
||||
/// </summary>
|
||||
/// <remarks>A page (or block) is 512 bytes long.</remarks>
|
||||
public ushort Pages;
|
||||
|
||||
/// <summary>
|
||||
/// Number of entries in the relocation table.
|
||||
/// </summary>
|
||||
public ushort RelocationItems;
|
||||
|
||||
/// <summary>
|
||||
/// The number of paragraphs taken up by the header. It can be any value, as the loader
|
||||
/// just uses it to find where the actual executable data starts. It may be larger than
|
||||
/// what the "standard" fields take up, and you may use it if you want to include your
|
||||
/// own header metadata, or put the relocation table there, or use it for any other purpose. [08]
|
||||
/// </summary>
|
||||
/// <remarks>A paragraph is 16 bytes in size</remarks>
|
||||
public ushort HeaderParagraphSize;
|
||||
|
||||
/// <summary>
|
||||
/// The number of paragraphs required by the program, excluding the PSP and program image.
|
||||
/// If no free block is big enough, the loading stops.
|
||||
/// </summary>
|
||||
/// <remarks>A paragraph is 16 bytes in size</remarks>
|
||||
public ushort MinimumExtraParagraphs;
|
||||
|
||||
/// <summary>
|
||||
/// The number of paragraphs requested by the program.
|
||||
/// If no free block is big enough, the biggest one possible is allocated.
|
||||
/// </summary>
|
||||
/// <remarks>A paragraph is 16 bytes in size</remarks>
|
||||
public ushort MaximumExtraParagraphs;
|
||||
|
||||
/// <summary>
|
||||
/// Relocatable segment address for SS.
|
||||
/// </summary>
|
||||
public ushort InitialSSValue;
|
||||
|
||||
/// <summary>
|
||||
/// Initial value for SP.
|
||||
/// </summary>
|
||||
public ushort InitialSPValue;
|
||||
|
||||
/// <summary>
|
||||
/// When added to the sum of all other words in the file, the result should be zero.
|
||||
/// </summary>
|
||||
public ushort Checksum;
|
||||
|
||||
/// <summary>
|
||||
/// Initial value for IP. [14]
|
||||
/// </summary>
|
||||
public ushort InitialIPValue;
|
||||
|
||||
/// <summary>
|
||||
/// Relocatable segment address for CS.
|
||||
/// </summary>
|
||||
public ushort InitialCSValue;
|
||||
|
||||
/// <summary>
|
||||
/// The (absolute) offset to the relocation table.
|
||||
/// </summary>
|
||||
public ushort RelocationTableAddr;
|
||||
|
||||
/// <summary>
|
||||
/// Value used for overlay management.
|
||||
/// If zero, this is the main executable.
|
||||
/// </summary>
|
||||
public ushort OverlayNumber;
|
||||
|
||||
#endregion
|
||||
|
||||
#region PE Extensions
|
||||
|
||||
/// <summary>
|
||||
/// Reserved words
|
||||
/// </summary>
|
||||
/// <remarks>4 entries/remarks>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public ushort[]? Reserved1;
|
||||
|
||||
/// <summary>
|
||||
/// Defined by name but no other information is given; typically zeroes
|
||||
/// </summary>
|
||||
public ushort OEMIdentifier;
|
||||
|
||||
/// <summary>
|
||||
/// Defined by name but no other information is given; typically zeroes
|
||||
/// </summary>
|
||||
public ushort OEMInformation;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved words
|
||||
/// </summary>
|
||||
/// <remarks>10 entries/remarks>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
|
||||
public ushort[]? Reserved2;
|
||||
|
||||
/// <summary>
|
||||
/// Starting address of the PE header
|
||||
/// </summary>
|
||||
public uint NewExeHeaderAddr;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
22
SabreTools.Serialization/Models/MSDOS/RelocationEntry.cs
Normal file
22
SabreTools.Serialization/Models/MSDOS/RelocationEntry.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.MSDOS
|
||||
{
|
||||
/// <summary>
|
||||
/// Each pointer in the relocation table looks as such
|
||||
/// </summary>
|
||||
/// <see href="https://wiki.osdev.org/MZ"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class RelocationEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset of the relocation within provided segment.
|
||||
/// </summary>
|
||||
public ushort Offset;
|
||||
|
||||
/// <summary>
|
||||
/// Segment of the relocation, relative to the load segment address.
|
||||
/// </summary>
|
||||
public ushort Segment;
|
||||
}
|
||||
}
|
||||
11
SabreTools.Serialization/Models/NewExecutable/Constants.cs
Normal file
11
SabreTools.Serialization/Models/NewExecutable/Constants.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly byte[] SignatureBytes = [0x4e, 0x45];
|
||||
|
||||
public const string SignatureString = "NE";
|
||||
|
||||
public const ushort SignatureUInt16 = 0x454e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry table follows the imported-name table. This table contains
|
||||
/// bundles of entry-point definitions. Bundling is done to save space in
|
||||
/// the entry table. The entry table is accessed by an ordinal value.
|
||||
/// Ordinal number one is defined to index the first entry in the entry
|
||||
/// table. To find an entry point, the bundles are scanned searching for a
|
||||
/// specific entry point using an ordinal number. The ordinal number is
|
||||
/// adjusted as each bundle is checked. When the bundle that contains the
|
||||
/// entry point is found, the ordinal number is multiplied by the size of
|
||||
/// the bundle's entries to index the proper entry.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The linker forms bundles in the most dense manner it can, under the
|
||||
/// restriction that it cannot reorder entry points to improve bundling.
|
||||
/// The reason for this restriction is that other .EXE files may refer to
|
||||
/// entry points within this bundle by their ordinal number. The following
|
||||
/// describes the format of the entry table bundles.
|
||||
/// </remarks>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
public sealed class EntryTableBundle
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of entries in this bundle. All records in one bundle
|
||||
/// are either moveable or refer to the same fixed segment. A zero
|
||||
/// value in this field indicates the end of the entry table.
|
||||
/// </summary>
|
||||
public byte EntryCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Segment indicator for this bundle. This defines the type of
|
||||
/// entry table entry data within the bundle. There are three
|
||||
/// types of entries that are defined.
|
||||
/// - 000h = Unused entries. There is no entry data in an unused
|
||||
/// bundle. The next bundle follows this field. This is
|
||||
/// used by the linker to skip ordinal numbers.
|
||||
/// - 001h-0FEh = Segment number for fixed segment entries. A fixed
|
||||
/// segment entry is 3 bytes long.
|
||||
/// - 0FFH = Moveable segment entries. The entry data contains the
|
||||
/// segment number for the entry points. A moveable segment
|
||||
/// entry is 6 bytes long.
|
||||
/// </summary>
|
||||
public byte SegmentIndicator { get; set; }
|
||||
|
||||
#region Fixed Segment Entry
|
||||
|
||||
/// <summary>
|
||||
/// Flag word.
|
||||
/// </summary>
|
||||
public FixedSegmentEntryFlag FixedFlagWord { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offset within segment to entry point.
|
||||
/// </summary>
|
||||
public ushort FixedOffset { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Moveable Segment Entry
|
||||
|
||||
/// <summary>
|
||||
/// Flag word.
|
||||
/// </summary>
|
||||
public MoveableSegmentEntryFlag MoveableFlagWord { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// INT 3FH.
|
||||
/// </summary>
|
||||
public ushort MoveableReserved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Segment number.
|
||||
/// </summary>
|
||||
public byte MoveableSegmentNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offset within segment to entry point.
|
||||
/// </summary>
|
||||
public ushort MoveableOffset { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
325
SabreTools.Serialization/Models/NewExecutable/Enums.cs
Normal file
325
SabreTools.Serialization/Models/NewExecutable/Enums.cs
Normal file
@@ -0,0 +1,325 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
[Flags]
|
||||
public enum FixedSegmentEntryFlag : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Set if the entry is exported.
|
||||
/// </summary>
|
||||
Exported = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Set if the entry uses a global (shared) data segments.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The first assembly-language instruction in the
|
||||
/// entry point prologue must be "MOV AX,data
|
||||
/// segment number". This may be set only for
|
||||
/// SINGLEDATA library modules.
|
||||
/// </remarks>
|
||||
Global = 0x02,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum HeaderFlag : ushort
|
||||
{
|
||||
#region Program Flags
|
||||
|
||||
NOAUTODATA = 0x0000,
|
||||
|
||||
/// <summary>
|
||||
/// Shared automatic data segment
|
||||
/// </summary>
|
||||
SINGLEDATA = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// Instanced automatic data segment
|
||||
/// </summary>
|
||||
MULTIPLEDATA = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// Global initialization
|
||||
/// </summary>
|
||||
GlobalInitialization = 0x0004,
|
||||
|
||||
/// <summary>
|
||||
/// Protected mode only
|
||||
/// </summary>
|
||||
ProtectedModeOnly = 0x0008,
|
||||
|
||||
/// <summary>
|
||||
/// 8086 instructions
|
||||
/// </summary>
|
||||
Instructions8086 = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// 80286 instructions
|
||||
/// </summary>
|
||||
Instructions80286 = 0x0020,
|
||||
|
||||
/// <summary>
|
||||
/// 80386 instructions
|
||||
/// </summary>
|
||||
Instructions80386 = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// 80x87 instructions
|
||||
/// </summary>
|
||||
Instructions80x87 = 0x0080,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Application Flags
|
||||
|
||||
/// <summary>
|
||||
/// Full screen (not aware of Windows/P.M. API)
|
||||
/// </summary>
|
||||
FullScreen = 0x0100,
|
||||
|
||||
/// <summary>
|
||||
/// Compatible with Windows/P.M. API
|
||||
/// </summary>
|
||||
WindowsPMCompatible = 0x0200,
|
||||
|
||||
/// <summary>
|
||||
/// Uses Windows/P.M. API
|
||||
/// </summary>
|
||||
WindowsPM = 0x0400,
|
||||
|
||||
/// <summary>
|
||||
/// OS/2 family application
|
||||
/// </summary>
|
||||
OS2FamilyApplication = 0x0800,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown (Reserved?)
|
||||
/// </summary>
|
||||
UnknownReserved = 0x1000,
|
||||
|
||||
/// <summary>
|
||||
/// Errors detected at link time, module will not load
|
||||
/// </summary>
|
||||
ErrorsDetectedAtLinkTime = 0x2000,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown (non-conforming program)
|
||||
/// </summary>
|
||||
UnknownNonConforming = 0x4000,
|
||||
|
||||
/// <summary>
|
||||
/// Library module.
|
||||
/// The SS:SP information is invalid, CS:IP points
|
||||
/// to an initialization procedure that is called
|
||||
/// with AX equal to the module handle. This
|
||||
/// initialization procedure must perform a far
|
||||
/// return to the caller, with AX not equal to
|
||||
/// zero to indicate success, or AX equal to zero
|
||||
/// to indicate failure to initialize. DS is set
|
||||
/// to the library's data segment if the
|
||||
/// SINGLEDATA flag is set. Otherwise, DS is set
|
||||
/// to the caller's data segment.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A program or DLL can only contain dynamic
|
||||
/// links to executable files that have this
|
||||
/// library module flag set. One program cannot
|
||||
/// dynamic-link to another program.
|
||||
/// </remarks>
|
||||
LibraryModule = 0x8000,
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum MoveableSegmentEntryFlag : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Set if the entry is exported.
|
||||
/// </summary>
|
||||
Exported = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Set if the entry uses a global (shared) data segments.
|
||||
/// </summary>
|
||||
Global = 0x02,
|
||||
}
|
||||
|
||||
public enum OperatingSystem : byte
|
||||
{
|
||||
Unknown = 0x00,
|
||||
OS2 = 0x01,
|
||||
WINDOWS = 0x02,
|
||||
EU_MSDOS4 = 0x03,
|
||||
WINDOWS_386 = 0x04,
|
||||
BOSS = 0x05,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum OS2Flag : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Long filename support
|
||||
/// </summary>
|
||||
LongFilenameSupport = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// 2.x protected mode
|
||||
/// </summary>
|
||||
ProtectedMode = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// 2.x proportional fonts
|
||||
/// </summary>
|
||||
ProportionalFonts = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// Executable has gangload area
|
||||
/// </summary>
|
||||
HasGangload = 0x08,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
Unknown = 0xF0,
|
||||
}
|
||||
|
||||
public enum OSFixupType : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// FIARQQ, FJARQQ
|
||||
/// </summary>
|
||||
FIARQQ = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// FISRQQ, FJSRQQ
|
||||
/// </summary>
|
||||
FISRQQ = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// FICRQQ, FJCRQQ
|
||||
/// </summary>
|
||||
FICRQQ = 0x0003,
|
||||
|
||||
FIERQQ = 0x0004,
|
||||
|
||||
FIDRQQ = 0x0005,
|
||||
|
||||
FIWRQQ = 0x0006,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum RelocationRecordFlag : byte
|
||||
{
|
||||
TARGET_MASK = 0x03,
|
||||
|
||||
INTERNALREF = 0x00,
|
||||
|
||||
IMPORTORDINAL = 0x01,
|
||||
|
||||
IMPORTNAME = 0x02,
|
||||
|
||||
OSFIXUP = 0x03,
|
||||
|
||||
ADDITIVE = 0x04,
|
||||
}
|
||||
|
||||
public enum RelocationRecordSourceType : byte
|
||||
{
|
||||
SOURCE_MASK = 0x0F,
|
||||
|
||||
LOBYTE = 0x00,
|
||||
|
||||
SEGMENT = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit pointer
|
||||
/// </summary>
|
||||
FAR_ADDR = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// 16-bit offset
|
||||
/// </summary>
|
||||
OFFSET = 0x05,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ResourceTypeResourceFlag : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Resource is not fixed.
|
||||
/// </summary>
|
||||
MOVEABLE = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// Resource can be shared.
|
||||
/// </summary>
|
||||
PURE = 0x0020,
|
||||
|
||||
/// <summary>
|
||||
/// Resource is preloaded.
|
||||
/// </summary>
|
||||
PRELOAD = 0x0040,
|
||||
}
|
||||
|
||||
public enum SegmentEntryType
|
||||
{
|
||||
/// <summary>
|
||||
/// 000h - There is no entry data in an unused bundle. The next bundle
|
||||
/// follows this field. This is used by the linker to skip ordinal numbers.
|
||||
/// </summary>
|
||||
Unused,
|
||||
|
||||
/// <summary>
|
||||
/// 001h-0FEh - Segment number for fixed segment entries. A fixed segment
|
||||
/// entry is 3 bytes long.
|
||||
/// </summary>
|
||||
FixedSegment,
|
||||
|
||||
/// <summary>
|
||||
/// 0FFH - Moveable segment entries. The entry data contains the segment
|
||||
/// number for the entry points. A moveable segment entry is 6 bytes long.
|
||||
/// </summary>
|
||||
MoveableSegment,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum SegmentTableEntryFlag : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Segment-type field.
|
||||
/// </summary>
|
||||
TYPE_MASK = 0x0007,
|
||||
|
||||
/// <summary>
|
||||
/// Code-segment type.
|
||||
/// </summary>
|
||||
CODE = 0x0000,
|
||||
|
||||
/// <summary>
|
||||
/// Data-segment type.
|
||||
/// </summary>
|
||||
DATA = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// Segment is not fixed.
|
||||
/// </summary>
|
||||
MOVEABLE = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// Segment will be preloaded; read-only if this is a data segment.
|
||||
/// </summary>
|
||||
PRELOAD = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// Set if segment has relocation records.
|
||||
/// </summary>
|
||||
RELOCINFO = 0x0100,
|
||||
|
||||
/// <summary>
|
||||
/// Discard priority.
|
||||
/// </summary>
|
||||
DISCARD = 0xF000,
|
||||
}
|
||||
}
|
||||
67
SabreTools.Serialization/Models/NewExecutable/Executable.cs
Normal file
67
SabreTools.Serialization/Models/NewExecutable/Executable.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The segmented EXE header contains general information about the EXE
|
||||
/// file and contains information on the location and size of the other
|
||||
/// sections. The Windows loader copies this section, along with other
|
||||
/// data, into the module table in the system data. The module table is
|
||||
/// internal data used by the loader to manage the loaded executable
|
||||
/// modules in the system and to support dynamic linking.
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
/// <see href="https://wiki.osdev.org/NE"/>
|
||||
public sealed class Executable
|
||||
{
|
||||
/// <summary>
|
||||
/// MS-DOS executable stub
|
||||
/// </summary>
|
||||
public MSDOS.Executable? Stub { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// New Executable header
|
||||
/// </summary>
|
||||
public ExecutableHeader? Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Segment table
|
||||
/// </summary>
|
||||
public SegmentTableEntry[]? SegmentTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Resource table
|
||||
/// </summary>
|
||||
public ResourceTable? ResourceTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Resident-Name table
|
||||
/// </summary>
|
||||
public ResidentNameTableEntry[]? ResidentNameTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Module-Reference table
|
||||
/// </summary>
|
||||
public ModuleReferenceTableEntry[]? ModuleReferenceTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Imported-Name table
|
||||
/// </summary>
|
||||
public Dictionary<ushort, ImportedNameTableEntry>? ImportedNameTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Entry table
|
||||
/// </summary>
|
||||
public EntryTableBundle[]? EntryTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Nonresident-Name table
|
||||
/// </summary>
|
||||
public NonResidentNameTableEntry[]? NonResidentNameTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Segment relocation data
|
||||
/// </summary>
|
||||
public PerSegmentData[]? SegmentRelocationData { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The NE header is a relatively large structure with multiple characteristics.
|
||||
/// Because of the age of the format some items are unclear in meaning.
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
/// <see href="https://github.com/libyal/libexe/blob/main/documentation/Executable%20(EXE)%20file%20format.asciidoc#24-ne-extended-header"/>
|
||||
/// <see href="https://wiki.osdev.org/NE"/>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
public sealed class ExecutableHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// "NE"
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
|
||||
public string? Magic;
|
||||
|
||||
/// <summary>
|
||||
/// Version number of the linker.
|
||||
/// </summary>
|
||||
/// <remarks>Also known as the major linker version</remarks>
|
||||
public byte LinkerVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Revision number of the linker.
|
||||
/// </summary>
|
||||
/// <remarks>Also known as the minor linker version</remarks>
|
||||
public byte LinkerRevision;
|
||||
|
||||
/// <summary>
|
||||
/// Entry Table file offset, relative to the beginning of the segmented EXE header.
|
||||
/// </summary>
|
||||
public ushort EntryTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Length of entry table in bytes
|
||||
/// </summary>
|
||||
public ushort EntryTableSize;
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit CRC of entire contents of file.
|
||||
/// </summary>
|
||||
/// <remarks>These words are taken as 00 during the calculation.</remarks>
|
||||
public uint CrcChecksum;
|
||||
|
||||
/// <summary>
|
||||
/// Flag word
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public HeaderFlag FlagWord;
|
||||
|
||||
/// <summary>
|
||||
/// Segment number of automatic data segment.
|
||||
/// This value is set to zero if SINGLEDATA and
|
||||
/// MULTIPLEDATA flag bits are clear, NOAUTODATA is
|
||||
/// indicated in the flags word.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A Segment number is an index into the module's segment
|
||||
/// table. The first entry in the segment table is segment
|
||||
/// number 1.
|
||||
/// </remarks>
|
||||
public ushort AutomaticDataSegmentNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Initial size, in bytes, of dynamic heap added to the
|
||||
/// data segment. This value is zero if no initial local
|
||||
/// heap is allocated.
|
||||
/// </summary>
|
||||
public ushort InitialHeapAlloc;
|
||||
|
||||
/// <summary>
|
||||
/// Initial size, in bytes, of stack added to the data
|
||||
/// segment. This value is zero to indicate no initial
|
||||
/// stack allocation, or when SS is not equal to DS.
|
||||
/// </summary>
|
||||
public ushort InitialStackAlloc;
|
||||
|
||||
/// <summary>
|
||||
/// Segment number:offset of CS:IP.
|
||||
/// </summary>
|
||||
/// <remarks>CS:IP entry point, CS is index into segment table</remarks>
|
||||
public uint InitialCSIPSetting;
|
||||
|
||||
/// <summary>
|
||||
/// Segment number:offset of SS:SP.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// SS:SP initial stack pointer, SS is index into segment table
|
||||
///
|
||||
/// If SS equals the automatic data segment and SP equals
|
||||
/// zero, the stack pointer is set to the top of the
|
||||
/// automatic data segment just below the additional heap
|
||||
/// area.
|
||||
/// </remarks>
|
||||
public uint InitialSSSPSetting;
|
||||
|
||||
/// <summary>
|
||||
/// Number of entries in the Segment Table.
|
||||
/// </summary>
|
||||
public ushort FileSegmentCount;
|
||||
|
||||
/// <summary>
|
||||
/// Number of entries in the Module Reference Table.
|
||||
/// </summary>
|
||||
public ushort ModuleReferenceTableSize;
|
||||
|
||||
/// <summary>
|
||||
/// Size of non-resident names table in bytes
|
||||
/// </summary>
|
||||
public ushort NonResidentNameTableSize;
|
||||
|
||||
/// <summary>
|
||||
/// Segment Table file offset, relative to the beginning
|
||||
/// of the segmented EXE header.
|
||||
/// </summary>
|
||||
public ushort SegmentTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Resource Table file offset, relative to the beginning
|
||||
/// of the segmented EXE header.
|
||||
/// </summary>
|
||||
public ushort ResourceTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Resident Name Table file offset, relative to the
|
||||
/// beginning of the segmented EXE header.
|
||||
/// </summary>
|
||||
public ushort ResidentNameTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Module Reference Table file offset, relative to the
|
||||
/// beginning of the segmented EXE header.
|
||||
/// </summary>
|
||||
public ushort ModuleReferenceTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Imported Names Table file offset, relative to the
|
||||
/// beginning of the segmented EXE header.
|
||||
/// </summary>
|
||||
public ushort ImportedNamesTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Non-Resident Name Table offset, relative to the
|
||||
/// beginning of the file.
|
||||
/// </summary>
|
||||
public uint NonResidentNamesTableOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Number of movable entries in the Entry Table.
|
||||
/// </summary>
|
||||
public ushort MovableEntriesCount;
|
||||
|
||||
/// <summary>
|
||||
/// Logical sector alignment shift count, log(base 2) of
|
||||
/// the segment sector size (default 9).
|
||||
/// </summary>
|
||||
public ushort SegmentAlignmentShiftCount;
|
||||
|
||||
/// <summary>
|
||||
/// Number of resource entries.
|
||||
/// </summary>
|
||||
public ushort ResourceEntriesCount;
|
||||
|
||||
/// <summary>
|
||||
/// Executable type, used by loader.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U1)]
|
||||
public OperatingSystem TargetOperatingSystem;
|
||||
|
||||
#region OS/2 Specific
|
||||
|
||||
/// <summary>
|
||||
/// Other OS/2 flags
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U1)]
|
||||
public OS2Flag AdditionalFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Offset to return thunks or start of gangload area
|
||||
/// </summary>
|
||||
public ushort ReturnThunkOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Offset to segment reference thunks or size of gangload area
|
||||
/// </summary>
|
||||
public ushort SegmentReferenceThunkOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum code swap area size
|
||||
/// </summary>
|
||||
public ushort MinCodeSwapAreaSize;
|
||||
|
||||
/// <summary>
|
||||
/// Windows SDK revison number
|
||||
/// </summary>
|
||||
public byte WindowsSDKRevision;
|
||||
|
||||
/// <summary>
|
||||
/// Windows SDK version number
|
||||
/// </summary>
|
||||
public byte WindowsSDKVersion;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class ImportNameRelocationRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// Index into module reference table for the imported module.
|
||||
/// </summary>
|
||||
public ushort Index;
|
||||
|
||||
/// <summary>
|
||||
/// Offset within Imported Names Table to procedure name string.
|
||||
/// </summary>
|
||||
public ushort Offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class ImportOrdinalRelocationRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// Index into module reference table for the imported module.
|
||||
/// </summary>
|
||||
public ushort Index;
|
||||
|
||||
/// <summary>
|
||||
/// Procedure ordinal number.
|
||||
/// </summary>
|
||||
public ushort Ordinal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The imported-name table follows the module-reference table. This table
|
||||
/// contains the names of modules and procedures that are imported by the
|
||||
/// executable file. Each entry is composed of a 1-byte field that
|
||||
/// contains the length of the string, followed by any number of
|
||||
/// characters. The strings are not null-terminated and are case
|
||||
/// sensitive.
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
public sealed class ImportedNameTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of the name string that follows. A zero value indicates
|
||||
/// the end of the name table.
|
||||
/// </summary>
|
||||
public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
|
||||
|
||||
/// <summary>
|
||||
/// ASCII text of the name string.
|
||||
/// </summary>
|
||||
public byte[]? NameString { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class InternalRefRelocationRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// Segment number for a fixed segment, or 0FFh for a
|
||||
/// movable segment.
|
||||
/// </summary>
|
||||
public byte SegmentNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Always 0
|
||||
/// </summary>
|
||||
public byte Reserved;
|
||||
|
||||
/// <summary>
|
||||
/// Offset into segment if fixed segment, or ordinal
|
||||
/// number index into Entry Table if movable segment.
|
||||
/// </summary>
|
||||
public ushort Offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The module-reference table follows the resident-name table. Each entry
|
||||
/// contains an offset for the module-name string within the imported-
|
||||
/// names table; each entry is 2 bytes long.
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class ModuleReferenceTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Offset within Imported Names Table to referenced module name string.
|
||||
/// </summary>
|
||||
public ushort Offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The nonresident-name table follows the entry table, and contains a
|
||||
/// module description and nonresident exported procedure name strings.
|
||||
/// The first string in this table is a module description. These name
|
||||
/// strings are case-sensitive and are not null-terminated. The name
|
||||
/// strings follow the same format as those defined in the resident name
|
||||
/// table.
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
public sealed class NonResidentNameTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of the name string that follows. A zero value indicates
|
||||
/// the end of the name table.
|
||||
/// </summary>
|
||||
public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
|
||||
|
||||
/// <summary>
|
||||
/// ASCII text of the name string.
|
||||
/// </summary>
|
||||
public byte[]? NameString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ordinal number (index into entry table). This value is ignored
|
||||
/// for the module name.
|
||||
/// </summary>
|
||||
public ushort OrdinalNumber { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class OSFixupRelocationRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// Operating system fixup type.
|
||||
/// Floating-point fixups.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public OSFixupType FixupType;
|
||||
|
||||
/// <summary>
|
||||
/// 0
|
||||
/// </summary>
|
||||
public ushort Reserved;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The location and size of the per-segment data is defined in the
|
||||
/// segment table entry for the segment. If the segment has relocation
|
||||
/// fixups, as defined in the segment table entry flags, they directly
|
||||
/// follow the segment data in the file. The relocation fixup information
|
||||
/// is defined as follows:
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// To find the relocation data for a segment, seek to:
|
||||
/// <see cref="SegmentTableEntry.Offset"/>
|
||||
/// * (1 << <see cref="ExecutableHeader.SegmentAlignmentShiftCount"/>)
|
||||
/// + <see cref="SegmentTableEntry.Length"/>
|
||||
/// </remarks>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
/// <see href="https://wiki.osdev.org/NE"/>
|
||||
public sealed class PerSegmentData
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of relocation records that follow.
|
||||
/// </summary>
|
||||
public ushort RelocationRecordCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A table of relocation records follows.
|
||||
/// </summary>
|
||||
public RelocationRecord[]? RelocationRecords { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// A table of relocation records follows. The following is the format
|
||||
/// of each relocation record.
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
public sealed class RelocationRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// Source type.
|
||||
/// </summary>
|
||||
public RelocationRecordSourceType SourceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flags byte.
|
||||
///
|
||||
/// The target value has four types that are defined in the flag
|
||||
/// byte field.
|
||||
/// </summary>
|
||||
public RelocationRecordFlag Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Offset within this segment of the source chain.
|
||||
/// If the ADDITIVE flag is set, then target value is added to
|
||||
/// the source contents, instead of replacing the source and
|
||||
/// following the chain. The source chain is an 0FFFFh
|
||||
/// terminated linked list within this segment of all
|
||||
/// references to the target.
|
||||
/// </summary>
|
||||
public ushort Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// INTERNALREF
|
||||
/// </summary>
|
||||
/// <remarks>Must be null if <see cref="Flags"/> is not set to <see cref="RelocationRecordFlag.INTERNALREF"/></remarks>
|
||||
public InternalRefRelocationRecord? InternalRefRelocationRecord { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IMPORTNAME
|
||||
/// </summary>
|
||||
/// <remarks>Must be null if <see cref="Flags"/> is not set to <see cref="RelocationRecordFlag.IMPORTNAME"/></remarks>
|
||||
public ImportNameRelocationRecord? ImportNameRelocationRecord { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IMPORTORDINAL
|
||||
/// </summary>
|
||||
/// <remarks>Must be null if <see cref="Flags"/> is not set to <see cref="RelocationRecordFlag.IMPORTORDINAL"/></remarks>
|
||||
public ImportOrdinalRelocationRecord? ImportOrdinalRelocationRecord { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IMPORTORDINAL
|
||||
/// </summary>
|
||||
/// <remarks>Must be null if <see cref="Flags"/> is not set to <see cref="RelocationRecordFlag.OSFIXUP"/></remarks>
|
||||
public OSFixupRelocationRecord? OSFixupRelocationRecord { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The resident-name table follows the resource table, and contains this
|
||||
/// module's name string and resident exported procedure name strings. The
|
||||
/// first string in this table is this module's name. These name strings
|
||||
/// are case-sensitive and are not null-terminated. The following
|
||||
/// describes the format of the name strings:
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
public sealed class ResidentNameTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of the name string that follows. A zero value indicates
|
||||
/// the end of the name table.
|
||||
/// </summary>
|
||||
public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
|
||||
|
||||
/// <summary>
|
||||
/// ASCII text of the name string.
|
||||
/// </summary>
|
||||
public byte[]? NameString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ordinal number (index into entry table). This value is ignored
|
||||
/// for the module name.
|
||||
/// </summary>
|
||||
public ushort OrdinalNumber { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The resource table follows the segment table and contains entries for
|
||||
/// each resource in the executable file. The resource table consists of
|
||||
/// an alignment shift count, followed by a table of resource records. The
|
||||
/// resource records define the type ID for a set of resources. Each
|
||||
/// resource record contains a table of resource entries of the defined
|
||||
/// type. The resource entry defines the resource ID or name ID for the
|
||||
/// resource. It also defines the location and size of the resource. The
|
||||
/// following describes the contents of each of these structures:
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
public sealed class ResourceTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Alignment shift count for resource data.
|
||||
/// </summary>
|
||||
public ushort AlignmentShiftCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A table of resource type information blocks follows.
|
||||
/// </summary>
|
||||
public ResourceTypeInformationEntry[]? ResourceTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Resource type and name strings are stored at the end of the
|
||||
/// resource table.
|
||||
/// </summary>
|
||||
public Dictionary<ushort, ResourceTypeAndNameString?>? TypeAndNameStrings { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// Resource type and name strings are stored at the end of the
|
||||
/// resource table. Note that these strings are NOT null terminated and
|
||||
/// are case sensitive.
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
public sealed class ResourceTypeAndNameString
|
||||
{
|
||||
/// <summary>
|
||||
/// Length of the type or name string that follows. A zero value
|
||||
/// indicates the end of the resource type and name string, also
|
||||
/// the end of the resource table.
|
||||
/// </summary>
|
||||
public byte Length { get; set; } // TODO: Remove in lieu of AnsiBStr
|
||||
|
||||
/// <summary>
|
||||
/// ASCII text of the type or name string.
|
||||
/// </summary>
|
||||
public byte[]? Text { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// A table of resource type information blocks follows. The following
|
||||
/// is the format of each type information block:
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
public sealed class ResourceTypeInformationEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Type ID. This is an integer type if the high-order bit is
|
||||
/// set (8000h); otherwise, it is an offset to the type string,
|
||||
/// the offset is relative to the beginning of the resource
|
||||
/// table. A zero type ID marks the end of the resource type
|
||||
/// information blocks.
|
||||
/// </summary>
|
||||
public ushort TypeID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of resources for this type.
|
||||
/// </summary>
|
||||
public ushort ResourceCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reserved.
|
||||
/// </summary>
|
||||
public uint Reserved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A table of resources for this type follows.
|
||||
/// </summary>
|
||||
public ResourceTypeResourceEntry[]? Resources { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// A table of resources for this type follows. The following is
|
||||
/// the format of each resource (8 bytes each):
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
/// <see href="https://wiki.osdev.org/NE"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class ResourceTypeResourceEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// File offset to the contents of the resource data,
|
||||
/// relative to beginning of file. The offset is in terms
|
||||
/// of the alignment shift count value specified at
|
||||
/// beginning of the resource table.
|
||||
/// </summary>
|
||||
/// <remarks>Byte offset is: Offset * (1 << <see cref="ResourceTable.AlignmentShiftCount"/>)</remarks>
|
||||
public ushort Offset;
|
||||
|
||||
/// <summary>
|
||||
/// Length of the resource in the file (in bytes).
|
||||
/// </summary>
|
||||
/// <remarks>Byte length is: Length * (1 << <see cref="ResourceTable.AlignmentShiftCount"/>)</remarks>
|
||||
public ushort Length;
|
||||
|
||||
/// <summary>
|
||||
/// Flag word.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public ResourceTypeResourceFlag FlagWord;
|
||||
|
||||
/// <summary>
|
||||
/// Resource ID. This is an integer type if the high-order
|
||||
/// bit is set (8000h), otherwise it is the offset to the
|
||||
/// resource string, the offset is relative to the
|
||||
/// beginning of the resource table.
|
||||
/// </summary>
|
||||
public ushort ResourceID;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved.
|
||||
/// </summary>
|
||||
public uint Reserved;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.NewExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The segment table contains an entry for each segment in the executable
|
||||
/// file. The number of segment table entries are defined in the segmented
|
||||
/// EXE header. The first entry in the segment table is segment number 1.
|
||||
/// The following is the structure of a segment table entry.
|
||||
/// </summary>
|
||||
/// <see href="https://web.archive.org/web/20240422070115/http://bytepointer.com/resources/win16_ne_exe_format_win3.0.htm"/>
|
||||
/// <see href="https://wiki.osdev.org/NE"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class SegmentTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Logical-sector offset (n byte) to the contents of the segment
|
||||
/// data, relative to the beginning of the file. Zero means no
|
||||
/// file data.
|
||||
/// </summary>
|
||||
/// <remarks>Byte offset is: Offset * (1 << <see cref="ExecutableHeader.SegmentAlignmentShiftCount"/>)</remarks>
|
||||
public ushort Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the segment in the file, in bytes. Zero means 64K.
|
||||
/// </summary>
|
||||
public ushort Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flag word.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U2)]
|
||||
public SegmentTableEntryFlag FlagWord;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum allocation size of the segment, in bytes. Total size
|
||||
/// of the segment. Zero means 64K.
|
||||
/// </summary>
|
||||
public ushort MinimumAllocationSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Segment data
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Data is not sequential to the entry header. It lives at
|
||||
/// the <see cref="Offset"/> and has a size of <see cref="Length"/>
|
||||
/// </remarks>
|
||||
public byte[]? Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Per-segment data
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This only exists if <see cref="FlagWord"/> has a flag value
|
||||
/// of <see cref="SegmentTableEntryFlag.RELOCINFO"/>. It immediately
|
||||
/// follows <see cref="Data"/>.
|
||||
/// </remarks>
|
||||
public PerSegmentData? PerSegmentData { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.AttributeCertificate
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute certificates can be associated with an image by adding an attribute
|
||||
/// certificate table. The attribute certificate table is composed of a set of
|
||||
/// contiguous, quadword-aligned attribute certificate entries. Zero padding is
|
||||
/// inserted between the original end of the file and the beginning of the attribute
|
||||
/// certificate table to achieve this alignment.
|
||||
///
|
||||
/// The virtual address value from the Certificate Table entry in the Optional
|
||||
/// Header Data Directory is a file offset to the first attribute certificate
|
||||
/// entry. Subsequent entries are accessed by advancing that entry's dwLength
|
||||
/// bytes, rounded up to an 8-byte multiple, from the start of the current
|
||||
/// attribute certificate entry. This continues until the sum of the rounded dwLength
|
||||
/// values equals the Size value from the Certificates Table entry in the Optional
|
||||
/// Header Data Directory. If the sum of the rounded dwLength values does not equal
|
||||
/// the Size value, then either the attribute certificate table or the Size field
|
||||
/// is corrupted.
|
||||
///
|
||||
/// The first certificate starts at offset 0x5000 from the start of the file on disk.
|
||||
/// To advance through all the attribute certificate entries:
|
||||
///
|
||||
/// 1. Add the first attribute certificate's dwLength value to the starting offset.
|
||||
/// 2. Round the value from step 1 up to the nearest 8-byte multiple to find the offset
|
||||
/// of the second attribute certificate entry.
|
||||
/// 3. Add the offset value from step 2 to the second attribute certificate entry's
|
||||
/// dwLength value and round up to the nearest 8-byte multiple to determine the offset
|
||||
/// of the third attribute certificate entry.
|
||||
/// 4. Repeat step 3 for each successive certificate until the calculated offset equals
|
||||
/// 0x6000 (0x5000 start + 0x1000 total size), which indicates that you've walked
|
||||
/// the entire table.
|
||||
///
|
||||
/// Attribute certificate table entries can contain any certificate type, as long as
|
||||
/// the entry has the correct dwLength value, a unique wRevision value, and a unique
|
||||
/// wCertificateType value. The most common type of certificate table entry is a
|
||||
/// WIN_CERTIFICATE structure, which is documented in Wintrust.h and discussed in
|
||||
/// the remainder of this section.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class Entry
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the length of the attribute certificate entry.
|
||||
/// </summary>
|
||||
public uint Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the certificate version number.
|
||||
/// </summary>
|
||||
public WindowsCertificateRevision Revision { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the type of content in Certificate.
|
||||
/// </summary>
|
||||
public WindowsCertificateType CertificateType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains a certificate, such as an Authenticode signature.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#certificate-data"/>
|
||||
public byte[]? Certificate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.BaseRelocation
|
||||
{
|
||||
/// <summary>
|
||||
/// The base relocation table contains entries for all base relocations in
|
||||
/// the image. The Base Relocation Table field in the optional header data
|
||||
/// directories gives the number of bytes in the base relocation table. For
|
||||
/// more information, see Optional Header Data Directories (Image Only).
|
||||
/// The base relocation table is divided into blocks. Each block represents
|
||||
/// the base relocations for a 4K page. Each block must start on a 32-bit boundary.
|
||||
///
|
||||
/// The loader is not required to process base relocations that are resolved by
|
||||
/// the linker, unless the load image cannot be loaded at the image base that is
|
||||
/// specified in the PE header.
|
||||
///
|
||||
/// To apply a base relocation, the difference is calculated between the preferred
|
||||
/// base address and the base where the image is actually loaded. If the image is
|
||||
/// loaded at its preferred base, the difference is zero and thus the base
|
||||
/// relocations do not have to be applied.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class Block
|
||||
{
|
||||
/// <summary>
|
||||
/// The image base plus the page RVA is added to each offset to create
|
||||
/// the VA where the base relocation must be applied.
|
||||
/// </summary>
|
||||
public uint PageRVA { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The total number of bytes in the base relocation block, including
|
||||
/// the Page RVA and Block Size fields and the Type/Offset fields that
|
||||
/// follow.
|
||||
/// </summary>
|
||||
public uint BlockSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Block Size field is then followed by any number of Type or Offset
|
||||
/// field entries. Each entry is a WORD (2 bytes) and has the following
|
||||
/// structure:
|
||||
///
|
||||
/// 4 bits - Type - Stored in the high 4 bits of the WORD, a value
|
||||
/// that indicates the type of base relocation to be
|
||||
/// applied. For more information, see <see cref="BaseRelocationTypes"/>
|
||||
/// 12 bits - Offset - Stored in the remaining 12 bits of the WORD, an
|
||||
/// offset from the starting address that was specified
|
||||
/// in the Page RVA field for the block. This offset
|
||||
/// specifies where the base relocation is to be applied.
|
||||
/// </summary>
|
||||
public TypeOffsetFieldEntry[]? TypeOffsetFieldEntries { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.BaseRelocation
|
||||
{
|
||||
/// <summary>
|
||||
/// Type or Offset field entry is a WORD (2 bytes).
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class TypeOffsetFieldEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Stored in the high 4 bits of the WORD, a value that indicates the type
|
||||
/// of base relocation to be applied. For more information, see <see cref="BaseRelocationTypes"/>
|
||||
/// </summary>
|
||||
public BaseRelocationTypes BaseRelocationType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stored in the remaining 12 bits of the WORD, an offset from the starting
|
||||
/// address that was specified in the Page RVA field for the block. This
|
||||
/// offset specifies where the base relocation is to be applied.
|
||||
/// </summary>
|
||||
public ushort Offset { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable
|
||||
{
|
||||
// TODO: Add more constants around sizes
|
||||
// - Debug Directory entry size is a constant value of 28 (0x1C)
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly byte[] SignatureBytes = [0x50, 0x45, 0x00, 0x00];
|
||||
|
||||
public const string SignatureString = "PE\0\0";
|
||||
|
||||
public const uint SignatureUInt32 = 0x00004550;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// Each data directory gives the address and size of a table or string that Windows uses.
|
||||
/// These data directory entries are all loaded into memory so that the system can use them
|
||||
/// at run time.
|
||||
///
|
||||
/// Also, do not assume that the RVAs in this table point to the beginning of a section or
|
||||
/// that the sections that contain specific tables have specific names.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class DataDirectory
|
||||
{
|
||||
/// <summary>
|
||||
/// The first field, VirtualAddress, is actually the RVA of the table. The RVA
|
||||
/// is the address of the table relative to the base address of the image when
|
||||
/// the table is loaded.
|
||||
/// </summary>
|
||||
public uint VirtualAddress;
|
||||
|
||||
/// <summary>
|
||||
/// The second field gives the size in bytes.
|
||||
/// </summary>
|
||||
public uint Size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.DebugData
|
||||
{
|
||||
/// <summary>
|
||||
/// Image files contain an optional debug directory that indicates what form
|
||||
/// of debug information is present and where it is. This directory consists
|
||||
/// of an array of debug directory entries whose location and size are indicated
|
||||
/// in the image optional header.
|
||||
///
|
||||
/// The debug directory can be in a discardable .debug section (if one exists),
|
||||
/// or it can be included in any other section in the image file, or not be in
|
||||
/// a section at all.
|
||||
///
|
||||
/// Each debug directory entry identifies the location and size of a block of
|
||||
/// debug information. The specified RVA can be zero if the debug information
|
||||
/// is not covered by a section header (that is, it resides in the image file
|
||||
/// and is not mapped into the run-time address space). If it is mapped, the
|
||||
/// RVA is its address.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class Entry
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved, must be zero.
|
||||
/// </summary>
|
||||
public uint Characteristics;
|
||||
|
||||
/// <summary>
|
||||
/// The time and date that the debug data was created.
|
||||
/// </summary>
|
||||
public uint TimeDateStamp;
|
||||
|
||||
/// <summary>
|
||||
/// The major version number of the debug data format.
|
||||
/// </summary>
|
||||
public ushort MajorVersion;
|
||||
|
||||
/// <summary>
|
||||
/// The minor version number of the debug data format.
|
||||
/// </summary>
|
||||
public ushort MinorVersion;
|
||||
|
||||
/// <summary>
|
||||
/// The format of debugging information. This field enables support
|
||||
/// of multiple debuggers.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.U4)]
|
||||
public DebugType DebugType;
|
||||
|
||||
/// <summary>
|
||||
/// The size of the debug data (not including the debug directory itself).
|
||||
/// </summary>
|
||||
public uint SizeOfData;
|
||||
|
||||
/// <summary>
|
||||
/// The address of the debug data when loaded, relative to the image base.
|
||||
/// </summary>
|
||||
public uint AddressOfRawData;
|
||||
|
||||
/// <summary>
|
||||
/// The file pointer to the debug data.
|
||||
/// </summary>
|
||||
public uint PointerToRawData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.DebugData
|
||||
{
|
||||
/// <summary>
|
||||
/// PDB 2.0 files
|
||||
/// </summary>
|
||||
/// <see href="https://www.debuginfo.com/articles/debuginfomatch.html"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class NB10ProgramDatabase
|
||||
{
|
||||
/// <summary>
|
||||
/// "CodeView signature, equal to “NB10”
|
||||
/// </summary>
|
||||
public uint Signature;
|
||||
|
||||
/// <summary>
|
||||
/// CodeView offset. Set to 0, because debug information
|
||||
/// is stored in a separate file.
|
||||
/// </summary>
|
||||
public uint Offset;
|
||||
|
||||
/// <summary>
|
||||
/// The time when debug information was created (in seconds
|
||||
/// since 01.01.1970)
|
||||
/// </summary>
|
||||
public uint Timestamp;
|
||||
|
||||
/// <summary>
|
||||
/// Ever-incrementing value, which is initially set to 1 and
|
||||
/// incremented every time when a part of the PDB file is updated
|
||||
/// without rewriting the whole file.
|
||||
/// </summary>
|
||||
public uint Age;
|
||||
|
||||
/// <summary>
|
||||
/// Null-terminated name of the PDB file. It can also contain full
|
||||
/// or partial path to the file.
|
||||
/// </summary>
|
||||
/// <remarks>Is this Unicode?</remarks>
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
public string? PdbFileName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.DebugData
|
||||
{
|
||||
/// <summary>
|
||||
/// This file describes the format of the pdb (Program Database) files of the "RSDS"
|
||||
/// or "DS" type which are emitted by Miscrosoft's link.exe from version 7 and above.
|
||||
/// </summary>
|
||||
/// <see href="http://www.godevtool.com/Other/pdb.htm"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class RSDSProgramDatabase
|
||||
{
|
||||
/// <summary>
|
||||
/// "RSDS" signature
|
||||
/// </summary>
|
||||
public uint Signature;
|
||||
|
||||
/// <summary>
|
||||
/// 16-byte Globally Unique Identifier
|
||||
/// </summary>
|
||||
public Guid GUID;
|
||||
|
||||
/// <summary>
|
||||
/// Ever-incrementing value, which is initially set to 1 and
|
||||
/// incremented every time when a part of the PDB file is updated
|
||||
/// without rewriting the whole file.
|
||||
/// </summary>
|
||||
public uint Age;
|
||||
|
||||
/// <summary>
|
||||
/// zero terminated UTF8 path and file name
|
||||
/// </summary>
|
||||
#if NET472_OR_GREATER || NETCOREAPP
|
||||
[MarshalAs(UnmanagedType.LPUTF8Str)]
|
||||
#else
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
#endif
|
||||
public string? PathAndFileName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.DebugData
|
||||
{
|
||||
/// <summary>
|
||||
/// The .debug section is used in object files to contain compiler-generated debug
|
||||
/// information and in image files to contain all of the debug information that is
|
||||
/// generated. This section describes the packaging of debug information in object
|
||||
/// and image files.
|
||||
///
|
||||
/// The next section describes the format of the debug directory, which can be
|
||||
/// anywhere in the image. Subsequent sections describe the "groups" in object
|
||||
/// files that contain debug information.
|
||||
///
|
||||
/// The default for the linker is that debug information is not mapped into the
|
||||
/// address space of the image. A .debug section exists only when debug information
|
||||
/// is mapped in the address space.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class Table
|
||||
{
|
||||
/// <summary>
|
||||
/// Image files contain an optional debug directory that indicates what form
|
||||
/// of debug information is present and where it is. This directory consists
|
||||
/// of an array of debug directory entries whose location and size are
|
||||
/// indicated in the image optional header.
|
||||
///
|
||||
/// The debug directory can be in a discardable .debug section (if one exists),
|
||||
/// or it can be included in any other section in the image file, or not be
|
||||
/// in a section at all.
|
||||
///
|
||||
/// Each debug directory entry identifies the location and size of a block of
|
||||
/// debug information. The specified RVA can be zero if the debug information
|
||||
/// is not covered by a section header (that is, it resides in the image
|
||||
/// file and is not mapped into the run-time address space). If it is mapped,
|
||||
/// the RVA is its address.
|
||||
/// </summary>
|
||||
public Entry[]? DebugDirectoryTable { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.DelayLoad
|
||||
{
|
||||
/// <summary>
|
||||
/// The delay-load directory table is the counterpart to the import directory
|
||||
/// table. It can be retrieved through the Delay Import Descriptor entry in
|
||||
/// the optional header data directories list (offset 200).
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class DirectoryTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Must be zero.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As yet, no attribute flags are defined. The linker sets this field to
|
||||
/// zero in the image. This field can be used to extend the record by
|
||||
/// indicating the presence of new fields, or it can be used to indicate
|
||||
/// behaviors to the delay or unload helper functions.
|
||||
/// </remarks>
|
||||
public uint Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// The RVA of the name of the DLL to be loaded. The name resides in the
|
||||
/// read-only data section of the image.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The name of the DLL to be delay-loaded resides in the read-only data
|
||||
/// section of the image. It is referenced through the szName field.
|
||||
/// </remarks>
|
||||
public uint NameRVA;
|
||||
|
||||
/// <summary>
|
||||
/// The RVA of the module handle (in the data section of the image) of the DLL
|
||||
/// to be delay-loaded. It is used for storage by the routine that is supplied
|
||||
/// to manage delay-loading.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The handle of the DLL to be delay-loaded is in the data section of the image.
|
||||
/// The phmod field points to the handle. The supplied delay-load helper uses
|
||||
/// this location to store the handle to the loaded DLL.
|
||||
/// </remarks>
|
||||
public uint ModuleHandle;
|
||||
|
||||
/// <summary>
|
||||
/// The RVA of the delay-load import address table.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The delay import address table (IAT) is referenced by the delay import
|
||||
/// descriptor through the pIAT field. The delay-load helper updates these
|
||||
/// pointers with the real entry points so that the thunks are no longer in
|
||||
/// the calling loop. The function pointers are accessed by using the expression
|
||||
/// pINT->u1.Function.
|
||||
/// </remarks>
|
||||
public uint DelayImportAddressTable;
|
||||
|
||||
/// <summary>
|
||||
/// The RVA of the delay-load name table, which contains the names of the imports
|
||||
/// that might need to be loaded. This matches the layout of the import name table.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The delay import name table (INT) contains the names of the imports that might
|
||||
/// require loading. They are ordered in the same fashion as the function pointers
|
||||
/// in the IAT. They consist of the same structures as the standard INT and are
|
||||
/// accessed by using the expression pINT->u1.AddressOfData->Name[0].
|
||||
/// </remarks>
|
||||
public uint DelayImportNameTable;
|
||||
|
||||
/// <summary>
|
||||
/// The RVA of the bound delay-load address table, if it exists.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The delay bound import address table (BIAT) is an optional table of
|
||||
/// IMAGE_THUNK_DATA items that is used along with the timestamp field of the
|
||||
/// delay-load directory table by a post-process binding phase.
|
||||
/// </remarks>
|
||||
public uint BoundDelayImportTable;
|
||||
|
||||
/// <summary>
|
||||
/// The RVA of the unload delay-load address table, if it exists. This is an exact
|
||||
/// copy of the delay import address table. If the caller unloads the DLL, this
|
||||
/// table should be copied back over the delay import address table so that
|
||||
/// subsequent calls to the DLL continue to use the thunking mechanism correctly.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The delay unload import address table (UIAT) is an optional table of
|
||||
/// IMAGE_THUNK_DATA items that the unload code uses to handle an explicit unload
|
||||
/// request. It consists of initialized data in the read-only section that is an
|
||||
/// exact copy of the original IAT that referred the code to the delay-load thunks.
|
||||
/// On the unload request, the library can be freed, the *phmod cleared, and the
|
||||
/// UIAT written over the IAT to restore everything to its preload state.
|
||||
/// </remarks>
|
||||
public uint UnloadDelayImportTable;
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp of the DLL to which this image has been bound.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The delay bound import address table (BIAT) is an optional table of
|
||||
/// IMAGE_THUNK_DATA items that is used along with the timestamp field of the
|
||||
/// delay-load directory table by a post-process binding phase.
|
||||
/// </remarks>
|
||||
public uint TimeStamp;
|
||||
}
|
||||
}
|
||||
1678
SabreTools.Serialization/Models/PortableExecutable/Enums.cs
Normal file
1678
SabreTools.Serialization/Models/PortableExecutable/Enums.cs
Normal file
File diff suppressed because it is too large
Load Diff
250
SabreTools.Serialization/Models/PortableExecutable/Executable.cs
Normal file
250
SabreTools.Serialization/Models/PortableExecutable/Executable.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The following list describes the Microsoft PE executable format, with the
|
||||
/// base of the image header at the top. The section from the MS-DOS 2.0
|
||||
/// Compatible EXE Header through to the unused section just before the PE header
|
||||
/// is the MS-DOS 2.0 Section, and is used for MS-DOS compatibility only.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class Executable
|
||||
{
|
||||
/// <summary>
|
||||
/// MS-DOS executable stub
|
||||
/// </summary>
|
||||
public MSDOS.Executable? Stub { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// After the MS-DOS stub, at the file offset specified at offset 0x3c, is a 4-byte
|
||||
/// signature that identifies the file as a PE format image file. This signature is "PE\0\0"
|
||||
/// (the letters "P" and "E" followed by two null bytes).
|
||||
/// </summary>
|
||||
public string? Signature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File header
|
||||
/// </summary>
|
||||
public COFF.FileHeader? FileHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Microsoft extended optional header
|
||||
/// </summary>
|
||||
public OptionalHeader? OptionalHeader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Section table
|
||||
/// </summary>
|
||||
public COFF.SectionHeader[]? SectionTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Symbol table
|
||||
/// </summary>
|
||||
public COFF.SymbolTableEntries.BaseEntry[]? SymbolTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// String table
|
||||
/// </summary>
|
||||
public COFF.StringTable? StringTable { get; set; }
|
||||
|
||||
#region Data Directories
|
||||
|
||||
/// <summary>
|
||||
/// The export data section, named .edata, contains information about symbols that other images
|
||||
/// can access through dynamic linking. Exported symbols are generally found in DLLs, but DLLs
|
||||
/// can also import symbols.
|
||||
///
|
||||
/// An overview of the general structure of the export section is described below. The tables
|
||||
/// described are usually contiguous in the file in the order shown (though this is not
|
||||
/// required). Only the export directory table and export address table are required to export
|
||||
/// symbols as ordinals. (An ordinal is an export that is accessed directly by its export
|
||||
/// address table index.) The name pointer table, ordinal table, and export name table all
|
||||
/// exist to support use of export names.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
#region Export Table (.edata)
|
||||
|
||||
/// <summary>
|
||||
/// A table with just one row (unlike the debug directory). This table indicates the
|
||||
/// locations and sizes of the other export tables.
|
||||
/// </summary>
|
||||
public Export.DirectoryTable? ExportDirectoryTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An array of RVAs of exported symbols. These are the actual addresses of the exported
|
||||
/// functions and data within the executable code and data sections. Other image files
|
||||
/// can import a symbol by using an index to this table (an ordinal) or, optionally, by
|
||||
/// using the public name that corresponds to the ordinal if a public name is defined.
|
||||
/// </summary>
|
||||
public Export.AddressTableEntry[]? ExportAddressTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An array of pointers to the public export names, sorted in ascending order.
|
||||
/// </summary>
|
||||
public Export.NamePointerTable? NamePointerTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An array of the ordinals that correspond to members of the name pointer table. The
|
||||
/// correspondence is by position; therefore, the name pointer table and the ordinal table
|
||||
/// must have the same number of members. Each ordinal is an index into the export address
|
||||
/// table.
|
||||
/// </summary>
|
||||
public Export.OrdinalTable? OrdinalTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A series of null-terminated ASCII strings. Members of the name pointer table point into
|
||||
/// this area. These names are the public names through which the symbols are imported and
|
||||
/// exported; they are not necessarily the same as the private names that are used within
|
||||
/// the image file.
|
||||
/// </summary>
|
||||
public Export.NameTable? ExportNameTable { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// All image files that import symbols, including virtually all executable (EXE) files,
|
||||
/// have an .idata section. A typical file layout for the import information follows:
|
||||
///
|
||||
/// - Directory Table
|
||||
/// Null Directory Entry
|
||||
/// - DLL1 Import Lookup Table
|
||||
/// Null
|
||||
/// - DLL2 Import Lookup Table
|
||||
/// Null
|
||||
/// - DLL3 Import Lookup Table
|
||||
/// Null
|
||||
/// - Hint-Name Table
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
#region Import Table (.idata) and Import Address Table
|
||||
|
||||
/// <summary>
|
||||
/// The import information begins with the import directory table, which describes the
|
||||
/// remainder of the import information.
|
||||
/// </summary>
|
||||
public Import.DirectoryTableEntry[]? ImportDirectoryTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An import lookup table is an array of 32-bit numbers for PE32 or an array of 64-bit
|
||||
/// numbers for PE32+.
|
||||
/// </summary>
|
||||
public Dictionary<int, Import.LookupTableEntry[]?>? ImportLookupTables { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// These addresses are the actual memory addresses of the symbols, although technically
|
||||
/// they are still called "virtual addresses".
|
||||
/// </summary>
|
||||
public Dictionary<int, Import.AddressTableEntry[]?>? ImportAddressTables { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// One hint/name table suffices for the entire import section.
|
||||
/// </summary>
|
||||
public Import.HintNameTableEntry[]? HintNameTable { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Resource Table (.rsrc)
|
||||
|
||||
/// <summary>
|
||||
/// Resource directory table (.rsrc)
|
||||
/// </summary>
|
||||
public Resource.DirectoryTable? ResourceDirectoryTable { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Handle Exception Table
|
||||
|
||||
#region Certificate Table
|
||||
|
||||
/// <summary>
|
||||
/// Attribute certificate table
|
||||
/// </summary>
|
||||
public AttributeCertificate.Entry[]? AttributeCertificateTable { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Base Relocation Table (.reloc)
|
||||
|
||||
/// <summary>
|
||||
/// Base relocation table
|
||||
/// </summary>
|
||||
public BaseRelocation.Block[]? BaseRelocationTable { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug Data (.debug*)
|
||||
|
||||
/// <summary>
|
||||
/// Debug table
|
||||
/// </summary>
|
||||
public DebugData.Table? DebugTable { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Handle Architecture
|
||||
// TODO: Handle Global Ptr
|
||||
// TODO: Thread Local Storage (.tls)
|
||||
// TODO: Load Configuration Table
|
||||
// TODO: Bound Import Table
|
||||
|
||||
#region Delay Load Table
|
||||
|
||||
/// <summary>
|
||||
/// Delay-load directory table
|
||||
/// </summary>
|
||||
public DelayLoad.DirectoryTable? DelayLoadDirectoryTable { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: CLR Runtime Header (.cormeta)
|
||||
// TODO: Reserved
|
||||
|
||||
#endregion
|
||||
|
||||
#region Named Sections
|
||||
|
||||
// TODO: Support grouped sections in section reading and parsing
|
||||
// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#grouped-sections-object-only
|
||||
// Grouped sections are ordered and mean that the data in the sections contributes
|
||||
// to the "base" section (the one without the "$X" suffix). This may negatively impact
|
||||
// the use of some of the different types of executables.
|
||||
|
||||
// .cormeta - CLR metadata is stored in this section. It is used to indicate that
|
||||
// the object file contains managed code. The format of the metadata is not
|
||||
// documented, but can be handed to the CLR interfaces for handling metadata.
|
||||
|
||||
// .drectve - A section is a directive section if it has the IMAGE_SCN_LNK_INFO
|
||||
// flag set in the section header and has the .drectve section name. The linker
|
||||
// removes a .drectve section after processing the information, so the section
|
||||
// does not appear in the image file that is being linked.
|
||||
//
|
||||
// A .drectve section consists of a string of text that can be encoded as ANSI
|
||||
// or UTF-8. If the UTF-8 byte order marker (BOM, a three-byte prefix that
|
||||
// consists of 0xEF, 0xBB, and 0xBF) is not present, the directive string is
|
||||
// interpreted as ANSI. The directive string is a series of linker options that
|
||||
// are separated by spaces. Each option contains a hyphen, the option name, and
|
||||
// any appropriate attribute. If an option contains spaces, the option must be
|
||||
// enclosed in quotes. The .drectve section must not have relocations or line
|
||||
// numbers.
|
||||
//
|
||||
// TODO: Can we implement reading/parsing the .drectve section?
|
||||
|
||||
// .pdata Section - Multiple formats per entry
|
||||
|
||||
// .sxdata - The valid exception handlers of an object are listed in the .sxdata
|
||||
// section of that object. The section is marked IMAGE_SCN_LNK_INFO. It contains
|
||||
// the COFF symbol index of each valid handler, using 4 bytes per index.
|
||||
//
|
||||
// Additionally, the compiler marks a COFF object as registered SEH by emitting
|
||||
// the absolute symbol "@feat.00" with the LSB of the value field set to 1. A
|
||||
// COFF object with no registered SEH handlers would have the "@feat.00" symbol,
|
||||
// but no .sxdata section.
|
||||
//
|
||||
// TODO: Can we implement reading/parsing the .sxdata section?
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Determine if "Archive (Library) File Format" is worth modelling
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.Export
|
||||
{
|
||||
/// <summary>
|
||||
/// The export address table contains the address of exported entry points
|
||||
/// and exported data and absolutes. An ordinal number is used as an index
|
||||
/// into the export address table.
|
||||
///
|
||||
/// Each entry in the export address table is a field that uses one of two
|
||||
/// formats in the following table. If the address specified is not within
|
||||
/// the export section (as defined by the address and length that are
|
||||
/// indicated in the optional header), the field is an export RVA, which is
|
||||
/// an actual address in code or data. Otherwise, the field is a forwarder RVA,
|
||||
/// which names a symbol in another DLL.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public sealed class AddressTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The address of the exported symbol when loaded into memory, relative to
|
||||
/// the image base. For example, the address of an exported function.
|
||||
/// </summary>
|
||||
[FieldOffset(0)] public uint ExportRVA;
|
||||
|
||||
/// <summary>
|
||||
/// The pointer to a null-terminated ASCII string in the export section. This
|
||||
/// string must be within the range that is given by the export table data
|
||||
/// directory entry. See Optional Header Data Directories (Image Only). This
|
||||
/// string gives the DLL name and the name of the export (for example,
|
||||
/// "MYDLL.expfunc") or the DLL name and the ordinal number of the export
|
||||
/// (for example, "MYDLL.#27").
|
||||
/// </summary>
|
||||
[FieldOffset(0)] public uint ForwarderRVA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.Export
|
||||
{
|
||||
/// <summary>
|
||||
/// The export symbol information begins with the export directory table,
|
||||
/// which describes the remainder of the export symbol information. The
|
||||
/// export directory table contains address information that is used to resolve
|
||||
/// imports to the entry points within this image.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class DirectoryTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Reserved, must be 0.
|
||||
/// </summary>
|
||||
public uint ExportFlags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The time and date that the export data was created.
|
||||
/// </summary>
|
||||
public uint TimeDateStamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The major version number. The major and minor version numbers can be set
|
||||
/// by the user.
|
||||
/// </summary>
|
||||
public ushort MajorVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The minor version number.
|
||||
/// </summary>
|
||||
public ushort MinorVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address of the ASCII string that contains the name of the DLL. This
|
||||
/// address is relative to the image base.
|
||||
/// </summary>
|
||||
public uint NameRVA { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ASCII string that contains the name of the DLL.
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The starting ordinal number for exports in this image. This field specifies
|
||||
/// the starting ordinal number for the export address table. It is usually set
|
||||
/// to 1.
|
||||
/// </summary>
|
||||
public uint OrdinalBase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of entries in the export address table.
|
||||
/// </summary>
|
||||
public uint AddressTableEntries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of entries in the name pointer table. This is also the number of
|
||||
/// entries in the ordinal table.
|
||||
/// </summary>
|
||||
public uint NumberOfNamePointers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address of the export address table, relative to the image base.
|
||||
/// </summary>
|
||||
public uint ExportAddressTableRVA { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address of the export name pointer table, relative to the image base.
|
||||
/// The table size is given by the Number of Name Pointers field.
|
||||
/// </summary>
|
||||
public uint NamePointerRVA { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address of the ordinal table, relative to the image base.
|
||||
/// </summary>
|
||||
public uint OrdinalTableRVA { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.Export
|
||||
{
|
||||
/// <summary>
|
||||
/// The export name pointer table is an array of addresses (RVAs) into the export name table.
|
||||
/// The pointers are 32 bits each and are relative to the image base. The pointers are ordered
|
||||
/// lexically to allow binary searches.
|
||||
///
|
||||
/// An export name is defined only if the export name pointer table contains a pointer to it.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class NamePointerTable
|
||||
{
|
||||
/// <summary>
|
||||
/// The pointers are 32 bits each and are relative to the image base.
|
||||
/// </summary>
|
||||
public uint[]? Pointers { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.Export
|
||||
{
|
||||
/// <summary>
|
||||
/// The export name table contains the actual string data that was pointed to by the export
|
||||
/// name pointer table. The strings in this table are public names that other images can use
|
||||
/// to import the symbols. These public export names are not necessarily the same as the
|
||||
/// private symbol names that the symbols have in their own image file and source code,
|
||||
/// although they can be.
|
||||
///
|
||||
/// Every exported symbol has an ordinal value, which is just the index into the export
|
||||
/// address table. Use of export names, however, is optional. Some, all, or none of the
|
||||
/// exported symbols can have export names. For exported symbols that do have export names,
|
||||
/// corresponding entries in the export name pointer table and export ordinal table work
|
||||
/// together to associate each name with an ordinal.
|
||||
///
|
||||
/// The structure of the export name table is a series of null-terminated ASCII strings
|
||||
/// of variable length.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class NameTable
|
||||
{
|
||||
/// <summary>
|
||||
/// A series of null-terminated ASCII strings of variable length.
|
||||
/// </summary>
|
||||
public string[]? Strings { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.Export
|
||||
{
|
||||
/// <summary>
|
||||
/// The export ordinal table is an array of 16-bit unbiased indexes into the export address table.
|
||||
/// Ordinals are biased by the Ordinal Base field of the export directory table. In other words,
|
||||
/// the ordinal base must be subtracted from the ordinals to obtain true indexes into the export
|
||||
/// address table.
|
||||
///
|
||||
/// The export name pointer table and the export ordinal table form two parallel arrays that are
|
||||
/// separated to allow natural field alignment. These two tables, in effect, operate as one table,
|
||||
/// in which the Export Name Pointer column points to a public (exported) name and the Export
|
||||
/// Ordinal column gives the corresponding ordinal for that public name. A member of the export
|
||||
/// name pointer table and a member of the export ordinal table are associated by having the same
|
||||
/// position (index) in their respective arrays.
|
||||
///
|
||||
/// Thus, when the export name pointer table is searched and a matching string is found at position
|
||||
/// i, the algorithm for finding the symbol's RVA and biased ordinal is:
|
||||
///
|
||||
/// i = Search_ExportNamePointerTable(name);
|
||||
/// ordinal = ExportOrdinalTable[i];
|
||||
///
|
||||
/// rva = ExportAddressTable[ordinal];
|
||||
/// biased_ordinal = ordinal + OrdinalBase;
|
||||
///
|
||||
/// When searching for a symbol by(biased) ordinal, the algorithm for finding the symbol's RVA
|
||||
/// and name is:
|
||||
///
|
||||
/// ordinal = biased_ordinal - OrdinalBase;
|
||||
/// i = Search_ExportOrdinalTable(ordinal);
|
||||
///
|
||||
/// rva = ExportAddressTable[ordinal];
|
||||
/// name = ExportNameTable[i];
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class OrdinalTable
|
||||
{
|
||||
/// <summary>
|
||||
/// An array of 16-bit unbiased indexes into the export address table
|
||||
/// </summary>
|
||||
public ushort[]? Indexes { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.Import
|
||||
{
|
||||
/// <summary>
|
||||
/// The structure and content of the import address table are identical to those of
|
||||
/// the import lookup table, until the file is bound. During binding, the entries in
|
||||
/// the import address table are overwritten with the 32-bit (for PE32) or 64-bit
|
||||
/// (for PE32+) addresses of the symbols that are being imported. These addresses are
|
||||
/// the actual memory addresses of the symbols, although technically they are still
|
||||
/// called "virtual addresses." The loader typically processes the binding.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class AddressTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// If this bit is set, import by ordinal. Otherwise, import by name. Bit is
|
||||
/// masked as 0x80000000 for PE32, 0x8000000000000000 for PE32+.
|
||||
/// </summary>
|
||||
/// <remarks>Bit 31/63</remarks>
|
||||
public bool OrdinalNameFlag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A 16-bit ordinal number. This field is used only if the Ordinal/Name Flag
|
||||
/// bit field is 1 (import by ordinal). Bits 30-15 or 62-15 must be 0.
|
||||
/// </summary>
|
||||
/// <remarks>Bits 15-0</remarks>
|
||||
public ushort OrdinalNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A 31-bit RVA of a hint/name table entry. This field is used only if the
|
||||
/// Ordinal/Name Flag bit field is 0 (import by name). For PE32+ bits 62-31
|
||||
/// must be zero.
|
||||
/// </summary>
|
||||
/// <remarks>Bits 30-0</remarks>
|
||||
public uint HintNameTableRVA { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.Import
|
||||
{
|
||||
/// <summary>
|
||||
/// The import information begins with the import directory table, which
|
||||
/// describes the remainder of the import information. The import directory
|
||||
/// table contains address information that is used to resolve fixup references
|
||||
/// to the entry points within a DLL image. The import directory table consists
|
||||
/// of an array of import directory entries, one entry for each DLL to which
|
||||
/// the image refers. The last directory entry is empty (filled with null values),
|
||||
/// which indicates the end of the directory table.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class DirectoryTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The RVA of the import lookup table. This table contains a name or ordinal
|
||||
/// for each import. (The name "Characteristics" is used in Winnt.h, but no
|
||||
/// longer describes this field.)
|
||||
/// </summary>
|
||||
public uint ImportLookupTableRVA { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The stamp that is set to zero until the image is bound. After the image is
|
||||
/// bound, this field is set to the time/data stamp of the DLL.
|
||||
/// </summary>
|
||||
public uint TimeDateStamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The index of the first forwarder reference.
|
||||
/// </summary>
|
||||
public uint ForwarderChain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address of an ASCII string that contains the name of the DLL. This address
|
||||
/// is relative to the image base.
|
||||
/// </summary>
|
||||
public uint NameRVA { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ASCII string that contains the name of the DLL.
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The RVA of the import address table. The contents of this table are identical
|
||||
/// to the contents of the import lookup table until the image is bound.
|
||||
/// </summary>
|
||||
public uint ImportAddressTableRVA { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.Import
|
||||
{
|
||||
/// <summary>
|
||||
/// One hint/name table suffices for the entire import section.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public sealed class HintNameTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// An index into the export name pointer table. A match is attempted first
|
||||
/// with this value. If it fails, a binary search is performed on the DLL's
|
||||
/// export name pointer table.
|
||||
/// </summary>
|
||||
public ushort Hint;
|
||||
|
||||
/// <summary>
|
||||
/// An ASCII string that contains the name to import. This is the string that
|
||||
/// must be matched to the public name in the DLL. This string is case sensitive
|
||||
/// and terminated by a null byte.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
public string? Name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
namespace SabreTools.Serialization.Models.PortableExecutable.Import
|
||||
{
|
||||
/// <summary>
|
||||
/// An import lookup table is an array of 32-bit numbers for PE32 or an array of
|
||||
/// 64-bit numbers for PE32+. Each entry uses the bit-field format that is described
|
||||
/// in the following table. In this format, bit 31 is the most significant bit for
|
||||
/// PE32 and bit 63 is the most significant bit for PE32+. The collection of these
|
||||
/// entries describes all imports from a given DLL. The last entry is set to zero
|
||||
/// (NULL) to indicate the end of the table.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public sealed class LookupTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// If this bit is set, import by ordinal. Otherwise, import by name. Bit is
|
||||
/// masked as 0x80000000 for PE32, 0x8000000000000000 for PE32+.
|
||||
/// </summary>
|
||||
/// <remarks>Bit 31/63</remarks>
|
||||
public bool OrdinalNameFlag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A 16-bit ordinal number. This field is used only if the Ordinal/Name Flag
|
||||
/// bit field is 1 (import by ordinal). Bits 30-15 or 62-15 must be 0.
|
||||
/// </summary>
|
||||
/// <remarks>Bits 15-0</remarks>
|
||||
public ushort OrdinalNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A 31-bit RVA of a hint/name table entry. This field is used only if the
|
||||
/// Ordinal/Name Flag bit field is 0 (import by name). For PE32+ bits 62-31
|
||||
/// must be zero.
|
||||
/// </summary>
|
||||
/// <remarks>Bits 30-0</remarks>
|
||||
public uint HintNameTableRVA { get; set; }
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user