using System; using System.IO; using System.Text; namespace BinaryObjectScanner.Wrappers { public class LinearExecutable : WrapperBase { #region Descriptive Properties /// public override string DescriptionString => "Linear Executable (LE/LX)"; #endregion #region Pass-Through Properties #region MS-DOS Stub #region Standard Fields /// #if NET48 public string Stub_Magic => this.Model.Stub.Header.Magic; #else public string? Stub_Magic => this.Model.Stub?.Header?.Magic; #endif /// #if NET48 public ushort Stub_LastPageBytes => this.Model.Stub.Header.LastPageBytes; #else public ushort? Stub_LastPageBytes => this.Model.Stub?.Header?.LastPageBytes; #endif /// #if NET48 public ushort Stub_Pages => this.Model.Stub.Header.Pages; #else public ushort? Stub_Pages => this.Model.Stub?.Header?.Pages; #endif /// #if NET48 public ushort Stub_RelocationItems => this.Model.Stub.Header.RelocationItems; #else public ushort? Stub_RelocationItems => this.Model.Stub?.Header?.RelocationItems; #endif /// #if NET48 public ushort Stub_HeaderParagraphSize => this.Model.Stub.Header.HeaderParagraphSize; #else public ushort? Stub_HeaderParagraphSize => this.Model.Stub?.Header?.HeaderParagraphSize; #endif /// #if NET48 public ushort Stub_MinimumExtraParagraphs => this.Model.Stub.Header.MinimumExtraParagraphs; #else public ushort? Stub_MinimumExtraParagraphs => this.Model.Stub?.Header?.MinimumExtraParagraphs; #endif /// #if NET48 public ushort Stub_MaximumExtraParagraphs => this.Model.Stub.Header.MaximumExtraParagraphs; #else public ushort? Stub_MaximumExtraParagraphs => this.Model.Stub?.Header?.MaximumExtraParagraphs; #endif /// #if NET48 public ushort Stub_InitialSSValue => this.Model.Stub.Header.InitialSSValue; #else public ushort? Stub_InitialSSValue => this.Model.Stub?.Header?.InitialSSValue; #endif /// #if NET48 public ushort Stub_InitialSPValue => this.Model.Stub.Header.InitialSPValue; #else public ushort? Stub_InitialSPValue => this.Model.Stub?.Header?.InitialSPValue; #endif /// #if NET48 public ushort Stub_Checksum => this.Model.Stub.Header.Checksum; #else public ushort? Stub_Checksum => this.Model.Stub?.Header?.Checksum; #endif /// #if NET48 public ushort Stub_InitialIPValue => this.Model.Stub.Header.InitialIPValue; #else public ushort? Stub_InitialIPValue => this.Model.Stub?.Header?.InitialIPValue; #endif /// #if NET48 public ushort Stub_InitialCSValue => this.Model.Stub.Header.InitialCSValue; #else public ushort? Stub_InitialCSValue => this.Model.Stub?.Header?.InitialCSValue; #endif /// #if NET48 public ushort Stub_RelocationTableAddr => this.Model.Stub.Header.RelocationTableAddr; #else public ushort? Stub_RelocationTableAddr => this.Model.Stub?.Header?.RelocationTableAddr; #endif /// #if NET48 public ushort Stub_OverlayNumber => this.Model.Stub.Header.OverlayNumber; #else public ushort? Stub_OverlayNumber => this.Model.Stub?.Header?.OverlayNumber; #endif #endregion #region PE Extensions /// #if NET48 public ushort[] Stub_Reserved1 => this.Model.Stub.Header.Reserved1; #else public ushort[]? Stub_Reserved1 => this.Model.Stub?.Header?.Reserved1; #endif /// #if NET48 public ushort Stub_OEMIdentifier => this.Model.Stub.Header.OEMIdentifier; #else public ushort? Stub_OEMIdentifier => this.Model.Stub?.Header?.OEMIdentifier; #endif /// #if NET48 public ushort Stub_OEMInformation => this.Model.Stub.Header.OEMInformation; #else public ushort? Stub_OEMInformation => this.Model.Stub?.Header?.OEMInformation; #endif /// #if NET48 public ushort[] Stub_Reserved2 => this.Model.Stub.Header.Reserved2; #else public ushort[]? Stub_Reserved2 => Model?.Stub?.Header?.Reserved2; #endif /// #if NET48 public uint Stub_NewExeHeaderAddr => this.Model.Stub.Header.NewExeHeaderAddr; #else public uint? Stub_NewExeHeaderAddr => this.Model.Stub?.Header?.NewExeHeaderAddr; #endif #endregion #endregion #region Information Block /// #if NET48 public string Signature => this.Model.InformationBlock.Signature; #else public string? Signature => this.Model.InformationBlock?.Signature; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.ByteOrder ByteOrder => this.Model.InformationBlock.ByteOrder; #else public SabreTools.Models.LinearExecutable.ByteOrder? ByteOrder => this.Model.InformationBlock?.ByteOrder; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.WordOrder WordOrder => this.Model.InformationBlock.WordOrder; #else public SabreTools.Models.LinearExecutable.WordOrder? WordOrder => this.Model.InformationBlock?.WordOrder; #endif /// #if NET48 public uint ExecutableFormatLevel => this.Model.InformationBlock.ExecutableFormatLevel; #else public uint? ExecutableFormatLevel => this.Model.InformationBlock?.ExecutableFormatLevel; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.CPUType CPUType => this.Model.InformationBlock.CPUType; #else public SabreTools.Models.LinearExecutable.CPUType? CPUType => this.Model.InformationBlock?.CPUType; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.OperatingSystem ModuleOS => this.Model.InformationBlock.ModuleOS; #else public SabreTools.Models.LinearExecutable.OperatingSystem? ModuleOS => this.Model.InformationBlock?.ModuleOS; #endif /// #if NET48 public uint ModuleVersion => this.Model.InformationBlock.ModuleVersion; #else public uint? ModuleVersion => this.Model.InformationBlock?.ModuleVersion; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.ModuleFlags ModuleTypeFlags => this.Model.InformationBlock.ModuleTypeFlags; #else public SabreTools.Models.LinearExecutable.ModuleFlags? ModuleTypeFlags => this.Model.InformationBlock?.ModuleTypeFlags; #endif /// #if NET48 public uint ModuleNumberPages => this.Model.InformationBlock.ModuleNumberPages; #else public uint? ModuleNumberPages => this.Model.InformationBlock?.ModuleNumberPages; #endif /// #if NET48 public uint InitialObjectCS => this.Model.InformationBlock.InitialObjectCS; #else public uint? InitialObjectCS => this.Model.InformationBlock?.InitialObjectCS; #endif /// #if NET48 public uint InitialEIP => this.Model.InformationBlock.InitialEIP; #else public uint? InitialEIP => this.Model.InformationBlock?.InitialEIP; #endif /// #if NET48 public uint InitialObjectSS => this.Model.InformationBlock.InitialObjectSS; #else public uint? InitialObjectSS => this.Model.InformationBlock?.InitialObjectSS; #endif /// #if NET48 public uint InitialESP => this.Model.InformationBlock.InitialESP; #else public uint? InitialESP => this.Model.InformationBlock?.InitialESP; #endif /// #if NET48 public uint MemoryPageSize => this.Model.InformationBlock.MemoryPageSize; #else public uint? MemoryPageSize => this.Model.InformationBlock?.MemoryPageSize; #endif /// #if NET48 public uint BytesOnLastPage => this.Model.InformationBlock.BytesOnLastPage; #else public uint? BytesOnLastPage => this.Model.InformationBlock?.BytesOnLastPage; #endif /// #if NET48 public uint FixupSectionSize => this.Model.InformationBlock.FixupSectionSize; #else public uint? FixupSectionSize => this.Model.InformationBlock?.FixupSectionSize; #endif /// #if NET48 public uint FixupSectionChecksum => this.Model.InformationBlock.FixupSectionChecksum; #else public uint? FixupSectionChecksum => this.Model.InformationBlock?.FixupSectionChecksum; #endif /// #if NET48 public uint LoaderSectionSize => this.Model.InformationBlock.LoaderSectionSize; #else public uint? LoaderSectionSize => this.Model.InformationBlock?.LoaderSectionSize; #endif /// #if NET48 public uint LoaderSectionChecksum => this.Model.InformationBlock.LoaderSectionChecksum; #else public uint? LoaderSectionChecksum => this.Model.InformationBlock?.LoaderSectionChecksum; #endif /// #if NET48 public uint ObjectTableOffset => this.Model.InformationBlock.ObjectTableOffset; #else public uint? ObjectTableOffset => this.Model.InformationBlock?.ObjectTableOffset; #endif /// #if NET48 public uint ObjectTableCount => this.Model.InformationBlock.ObjectTableCount; #else public uint? ObjectTableCount => this.Model.InformationBlock?.ObjectTableCount; #endif /// #if NET48 public uint ObjectPageMapOffset => this.Model.InformationBlock.ObjectPageMapOffset; #else public uint? ObjectPageMapOffset => this.Model.InformationBlock?.ObjectPageMapOffset; #endif /// #if NET48 public uint ObjectIterateDataMapOffset => this.Model.InformationBlock.ObjectIterateDataMapOffset; #else public uint? ObjectIterateDataMapOffset => this.Model.InformationBlock?.ObjectIterateDataMapOffset; #endif /// #if NET48 public uint ResourceTableOffset => this.Model.InformationBlock.ResourceTableOffset; #else public uint? ResourceTableOffset => this.Model.InformationBlock?.ResourceTableOffset; #endif /// #if NET48 public uint ResourceTableCount => this.Model.InformationBlock.ResourceTableCount; #else public uint? ResourceTableCount => this.Model.InformationBlock?.ResourceTableCount; #endif /// #if NET48 public uint ResidentNamesTableOffset => this.Model.InformationBlock.ResidentNamesTableOffset; #else public uint? ResidentNamesTableOffset => this.Model.InformationBlock?.ResidentNamesTableOffset; #endif /// #if NET48 public uint EntryTableOffset => this.Model.InformationBlock.EntryTableOffset; #else public uint? EntryTableOffset => this.Model.InformationBlock?.EntryTableOffset; #endif /// #if NET48 public uint ModuleDirectivesTableOffset => this.Model.InformationBlock.ModuleDirectivesTableOffset; #else public uint? ModuleDirectivesTableOffset => this.Model.InformationBlock?.ModuleDirectivesTableOffset; #endif /// #if NET48 public uint ModuleDirectivesCount => this.Model.InformationBlock.ModuleDirectivesCount; #else public uint? ModuleDirectivesCount => this.Model.InformationBlock?.ModuleDirectivesCount; #endif /// #if NET48 public uint FixupPageTableOffset => this.Model.InformationBlock.FixupPageTableOffset; #else public uint? FixupPageTableOffset => this.Model.InformationBlock?.FixupPageTableOffset; #endif /// #if NET48 public uint FixupRecordTableOffset => this.Model.InformationBlock.FixupRecordTableOffset; #else public uint? FixupRecordTableOffset => this.Model.InformationBlock?.FixupRecordTableOffset; #endif /// #if NET48 public uint ImportedModulesNameTableOffset => this.Model.InformationBlock.ImportedModulesNameTableOffset; #else public uint? ImportedModulesNameTableOffset => this.Model.InformationBlock?.ImportedModulesNameTableOffset; #endif /// #if NET48 public uint ImportedModulesCount => this.Model.InformationBlock.ImportedModulesCount; #else public uint? ImportedModulesCount => this.Model.InformationBlock?.ImportedModulesCount; #endif /// #if NET48 public uint ImportProcedureNameTableOffset => this.Model.InformationBlock.ImportProcedureNameTableOffset; #else public uint? ImportProcedureNameTableOffset => this.Model.InformationBlock?.ImportProcedureNameTableOffset; #endif /// #if NET48 public uint PerPageChecksumTableOffset => this.Model.InformationBlock.PerPageChecksumTableOffset; #else public uint? PerPageChecksumTableOffset => this.Model.InformationBlock?.PerPageChecksumTableOffset; #endif /// #if NET48 public uint DataPagesOffset => this.Model.InformationBlock.DataPagesOffset; #else public uint? DataPagesOffset => this.Model.InformationBlock?.DataPagesOffset; #endif /// #if NET48 public uint PreloadPageCount => this.Model.InformationBlock.PreloadPageCount; #else public uint? PreloadPageCount => this.Model.InformationBlock?.PreloadPageCount; #endif /// #if NET48 public uint NonResidentNamesTableOffset => this.Model.InformationBlock.NonResidentNamesTableOffset; #else public uint? NonResidentNamesTableOffset => this.Model.InformationBlock?.NonResidentNamesTableOffset; #endif /// #if NET48 public uint NonResidentNamesTableLength => this.Model.InformationBlock.NonResidentNamesTableLength; #else public uint? NonResidentNamesTableLength => this.Model.InformationBlock?.NonResidentNamesTableLength; #endif /// #if NET48 public uint NonResidentNamesTableChecksum => this.Model.InformationBlock.NonResidentNamesTableChecksum; #else public uint? NonResidentNamesTableChecksum => this.Model.InformationBlock?.NonResidentNamesTableChecksum; #endif /// #if NET48 public uint AutomaticDataObject => this.Model.InformationBlock.AutomaticDataObject; #else public uint? AutomaticDataObject => this.Model.InformationBlock?.AutomaticDataObject; #endif /// #if NET48 public uint DebugInformationOffset => this.Model.InformationBlock.DebugInformationOffset; #else public uint? DebugInformationOffset => this.Model.InformationBlock?.DebugInformationOffset; #endif /// #if NET48 public uint DebugInformationLength => this.Model.InformationBlock.DebugInformationLength; #else public uint? DebugInformationLength => this.Model.InformationBlock?.DebugInformationLength; #endif /// #if NET48 public uint PreloadInstancePagesNumber => this.Model.InformationBlock.PreloadInstancePagesNumber; #else public uint? PreloadInstancePagesNumber => this.Model.InformationBlock?.PreloadInstancePagesNumber; #endif /// #if NET48 public uint DemandInstancePagesNumber => this.Model.InformationBlock.DemandInstancePagesNumber; #else public uint? DemandInstancePagesNumber => this.Model.InformationBlock?.DemandInstancePagesNumber; #endif /// #if NET48 public uint ExtraHeapAllocation => this.Model.InformationBlock.ExtraHeapAllocation; #else public uint? ExtraHeapAllocation => this.Model.InformationBlock?.ExtraHeapAllocation; #endif #endregion #region Tables /// #if NET48 public SabreTools.Models.LinearExecutable.ObjectTableEntry[] ObjectTable => this.Model.ObjectTable; #else public SabreTools.Models.LinearExecutable.ObjectTableEntry?[]? ObjectTable => this.Model.ObjectTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.ObjectPageMapEntry[] ObjectPageMap => this.Model.ObjectPageMap; #else public SabreTools.Models.LinearExecutable.ObjectPageMapEntry?[]? ObjectPageMap => this.Model.ObjectPageMap; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.ResourceTableEntry[] ResourceTable => this.Model.ResourceTable; #else public SabreTools.Models.LinearExecutable.ResourceTableEntry?[]? ResourceTable => this.Model.ResourceTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.ResidentNamesTableEntry[] ResidentNamesTable => this.Model.ResidentNamesTable; #else public SabreTools.Models.LinearExecutable.ResidentNamesTableEntry?[]? ResidentNamesTable => this.Model.ResidentNamesTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.EntryTableBundle[] EntryTable => this.Model.EntryTable; #else public SabreTools.Models.LinearExecutable.EntryTableBundle?[]? EntryTable => this.Model.EntryTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.ModuleFormatDirectivesTableEntry[] ModuleFormatDirectivesTable => this.Model.ModuleFormatDirectivesTable; #else public SabreTools.Models.LinearExecutable.ModuleFormatDirectivesTableEntry?[]? ModuleFormatDirectivesTable => this.Model.ModuleFormatDirectivesTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.VerifyRecordDirectiveTableEntry[] VerifyRecordDirectiveTable => this.Model.VerifyRecordDirectiveTable; #else public SabreTools.Models.LinearExecutable.VerifyRecordDirectiveTableEntry?[]? VerifyRecordDirectiveTable => this.Model.VerifyRecordDirectiveTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.PerPageChecksumTableEntry[] PerPageChecksumTable => this.Model.PerPageChecksumTable; #else public SabreTools.Models.LinearExecutable.PerPageChecksumTableEntry?[]? PerPageChecksumTable => this.Model.PerPageChecksumTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.FixupPageTableEntry[] FixupPageTable => this.Model.FixupPageTable; #else public SabreTools.Models.LinearExecutable.FixupPageTableEntry?[]? FixupPageTable => this.Model.FixupPageTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.FixupRecordTableEntry[] FixupRecordTable => this.Model.FixupRecordTable; #else public SabreTools.Models.LinearExecutable.FixupRecordTableEntry?[]? FixupRecordTable => this.Model.FixupRecordTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.ImportModuleNameTableEntry[] ImportModuleNameTable => this.Model.ImportModuleNameTable; #else public SabreTools.Models.LinearExecutable.ImportModuleNameTableEntry?[]? ImportModuleNameTable => this.Model.ImportModuleNameTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.ImportModuleProcedureNameTableEntry[] ImportModuleProcedureNameTable => this.Model.ImportModuleProcedureNameTable; #else public SabreTools.Models.LinearExecutable.ImportModuleProcedureNameTableEntry?[]? ImportModuleProcedureNameTable => this.Model.ImportModuleProcedureNameTable; #endif /// #if NET48 public SabreTools.Models.LinearExecutable.NonResidentNamesTableEntry[] NonResidentNamesTable => this.Model.NonResidentNamesTable; #else public SabreTools.Models.LinearExecutable.NonResidentNamesTableEntry?[]? NonResidentNamesTable => this.Model.NonResidentNamesTable; #endif #endregion #region Debug Information /// #if NET48 public string DI_Signature => this.Model.DebugInformation?.Signature; #else public string? DI_Signature => this.Model.DebugInformation?.Signature; #endif /// public SabreTools.Models.LinearExecutable.DebugFormatType? DI_FormatType => this.Model.DebugInformation?.FormatType; /// #if NET48 public byte[] DebuggerData => this.Model.DebugInformation?.DebuggerData; #else public byte[]? DebuggerData => this.Model.DebugInformation?.DebuggerData; #endif #endregion #endregion #region Extension Properties // TODO: Determine what extension properties are needed #endregion #region Constructors /// #if NET48 public LinearExecutable(SabreTools.Models.LinearExecutable.Executable model, byte[] data, int offset) #else public LinearExecutable(SabreTools.Models.LinearExecutable.Executable? model, byte[]? data, int offset) #endif : base(model, data, offset) { // All logic is handled by the base class } /// #if NET48 public LinearExecutable(SabreTools.Models.LinearExecutable.Executable model, Stream data) #else public LinearExecutable(SabreTools.Models.LinearExecutable.Executable? model, Stream? data) #endif : base(model, data) { // All logic is handled by the base class }/// /// Create an LE/LX executable from a byte array and offset /// /// Byte array representing the executable /// Offset within the array to parse /// An LE/LX executable wrapper on success, null on failure #if NET48 public static LinearExecutable Create(byte[] data, int offset) #else public static LinearExecutable? Create(byte[]? data, int offset) #endif { // If the data is invalid if (data == null) return null; // If the offset is out of bounds if (offset < 0 || offset >= data.Length) return null; // Create a memory stream and use that MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset); return Create(dataStream); } /// /// Create an LE/LX executable from a Stream /// /// Stream representing the executable /// An LE/LX executable wrapper on success, null on failure #if NET48 public static LinearExecutable Create(Stream data) #else public static LinearExecutable? Create(Stream? data) #endif { // If the data is invalid if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead) return null; var executable = new SabreTools.Serialization.Streams.LinearExecutable().Deserialize(data); if (executable == null) return null; try { return new LinearExecutable(executable, data); } catch { return null; } } #endregion #region Printing /// public override StringBuilder PrettyPrint() { StringBuilder builder = new StringBuilder(); Printing.LinearExecutable.Print(builder, this.Model); return builder; } #endregion #region REMOVE -- DO NOT USE /// /// Read an arbitrary range from the source /// /// The start of where to read data from, -1 means start of source /// How many bytes to read, -1 means read until end /// Byte array representing the range, null on error [Obsolete] #if NET48 public byte[] ReadArbitraryRange(int rangeStart = -1, int length = -1) #else public byte[]? ReadArbitraryRange(int rangeStart = -1, int length = -1) #endif { // If we have an unset range start, read from the start of the source if (rangeStart == -1) rangeStart = 0; // If we have an unset length, read the whole source if (length == -1) { switch (_dataSource) { case DataSource.ByteArray: #if NET48 length = _byteArrayData.Length - _byteArrayOffset; #else length = _byteArrayData!.Length - _byteArrayOffset; #endif break; case DataSource.Stream: #if NET48 length = (int)_streamData.Length; #else length = (int)_streamData!.Length; #endif break; } } return ReadFromDataSource(rangeStart, length); } #endregion } }