Files
BinaryObjectScanner/BinaryObjectScanner.Wrappers/PortableExecutable.cs

2835 lines
105 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.IO;
2022-12-02 22:24:22 -08:00
using System.Linq;
using System.Text;
using SabreTools.IO;
2023-09-10 23:51:38 -04:00
using static SabreTools.Serialization.Extensions;
2022-12-02 15:20:44 -08:00
2023-03-07 16:59:14 -05:00
namespace BinaryObjectScanner.Wrappers
2022-12-02 15:20:44 -08:00
{
2023-09-11 23:25:09 -04:00
public class PortableExecutable : WrapperBase<SabreTools.Models.PortableExecutable.Executable>
2022-12-02 15:20:44 -08:00
{
2023-01-18 11:18:53 -08:00
#region Descriptive Properties
/// <inheritdoc/>
2023-09-11 23:25:09 -04:00
public override string DescriptionString => "Portable Executable (PE)";
2023-01-18 11:18:53 -08:00
#endregion
2022-12-02 15:20:44 -08:00
#region Pass-Through Properties
2022-12-02 15:35:10 -08:00
#region MS-DOS Stub
#region Standard Fields
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.Magic"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public string Stub_Magic => _model.Stub.Header.Magic;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public string? Stub_Magic => _model.Stub?.Header?.Magic;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.LastPageBytes"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_LastPageBytes => _model.Stub.Header.LastPageBytes;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_LastPageBytes => _model.Stub?.Header?.LastPageBytes;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.Pages"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_Pages => _model.Stub.Header.Pages;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_Pages => _model.Stub?.Header?.Pages;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.RelocationItems"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_RelocationItems => _model.Stub.Header.RelocationItems;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_RelocationItems => _model.Stub?.Header?.RelocationItems;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.HeaderParagraphSize"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_HeaderParagraphSize => _model.Stub.Header.HeaderParagraphSize;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_HeaderParagraphSize => _model.Stub?.Header?.HeaderParagraphSize;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.MinimumExtraParagraphs"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_MinimumExtraParagraphs => _model.Stub.Header.MinimumExtraParagraphs;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_MinimumExtraParagraphs => _model.Stub?.Header?.MinimumExtraParagraphs;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.MaximumExtraParagraphs"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_MaximumExtraParagraphs => _model.Stub.Header.MaximumExtraParagraphs;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_MaximumExtraParagraphs => _model.Stub?.Header?.MaximumExtraParagraphs;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.InitialSSValue"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_InitialSSValue => _model.Stub.Header.InitialSSValue;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_InitialSSValue => _model.Stub?.Header?.InitialSSValue;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.InitialSPValue"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_InitialSPValue => _model.Stub.Header.InitialSPValue;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_InitialSPValue => _model.Stub?.Header?.InitialSPValue;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.Checksum"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_Checksum => _model.Stub.Header.Checksum;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_Checksum => _model.Stub?.Header?.Checksum;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.InitialIPValue"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_InitialIPValue => _model.Stub.Header.InitialIPValue;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_InitialIPValue => _model.Stub?.Header?.InitialIPValue;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.InitialCSValue"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_InitialCSValue => _model.Stub.Header.InitialCSValue;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_InitialCSValue => _model.Stub?.Header?.InitialCSValue;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.RelocationTableAddr"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_RelocationTableAddr => _model.Stub.Header.RelocationTableAddr;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_RelocationTableAddr => _model.Stub?.Header?.RelocationTableAddr;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.OverlayNumber"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_OverlayNumber => _model.Stub.Header.OverlayNumber;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_OverlayNumber => _model.Stub?.Header?.OverlayNumber;
#endif
2022-12-02 15:35:10 -08:00
#endregion
#region PE Extensions
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.Reserved1"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort[] Stub_Reserved1 => _model.Stub.Header.Reserved1;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public ushort[]? Stub_Reserved1 => _model.Stub?.Header?.Reserved1;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.OEMIdentifier"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_OEMIdentifier => _model.Stub.Header.OEMIdentifier;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_OEMIdentifier => _model.Stub?.Header?.OEMIdentifier;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.OEMInformation"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort Stub_OEMInformation => _model.Stub.Header.OEMInformation;
2023-09-13 00:08:11 -04:00
#else
public ushort? Stub_OEMInformation => _model.Stub?.Header?.OEMInformation;
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.Reserved2"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort[] Stub_Reserved2 => _model.Stub.Header.Reserved2;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public ushort[]? Stub_Reserved2 => _model.Stub?.Header?.Reserved2;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.NewExeHeaderAddr"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint Stub_NewExeHeaderAddr => _model.Stub.Header.NewExeHeaderAddr;
2023-09-13 00:08:11 -04:00
#else
public uint? Stub_NewExeHeaderAddr => _model.Stub?.Header?.NewExeHeaderAddr;
#endif
2022-12-02 15:35:10 -08:00
#endregion
#endregion
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.Executable.Signature"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public string Signature => _model.Signature;
2023-09-12 17:12:23 -04:00
#else
public string? Signature => _model.Signature;
#endif
2022-12-02 16:16:12 -08:00
#region COFF File Header
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.Machine"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.MachineType Machine => _model.COFFFileHeader.Machine;
2023-09-13 00:08:11 -04:00
#else
public SabreTools.Models.PortableExecutable.MachineType? Machine => _model.COFFFileHeader?.Machine;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.NumberOfSections"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort NumberOfSections => _model.COFFFileHeader.NumberOfSections;
2023-09-13 00:08:11 -04:00
#else
public ushort? NumberOfSections => _model.COFFFileHeader?.NumberOfSections;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.TimeDateStamp"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint TimeDateStamp => _model.COFFFileHeader.TimeDateStamp;
2023-09-13 00:08:11 -04:00
#else
public uint? TimeDateStamp => _model.COFFFileHeader?.TimeDateStamp;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.PointerToSymbolTable"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint PointerToSymbolTable => _model.COFFFileHeader.PointerToSymbolTable;
2023-09-13 00:08:11 -04:00
#else
public uint? PointerToSymbolTable => _model.COFFFileHeader?.PointerToSymbolTable;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.NumberOfSymbols"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint NumberOfSymbols => _model.COFFFileHeader.NumberOfSymbols;
2023-09-13 00:08:11 -04:00
#else
public uint? NumberOfSymbols => _model.COFFFileHeader?.NumberOfSymbols;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.SizeOfOptionalHeader"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint SizeOfOptionalHeader => _model.COFFFileHeader.SizeOfOptionalHeader;
2023-09-13 00:08:11 -04:00
#else
public uint? SizeOfOptionalHeader => _model.COFFFileHeader?.SizeOfOptionalHeader;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.Characteristics"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.Characteristics Characteristics => _model.COFFFileHeader.Characteristics;
2023-09-13 00:08:11 -04:00
#else
public SabreTools.Models.PortableExecutable.Characteristics? Characteristics => _model.COFFFileHeader?.Characteristics;
#endif
2022-12-02 16:16:12 -08:00
#endregion
#region Optional Header
#region Standard Fields
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Machine"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.OptionalHeaderMagicNumber OH_Magic => _model.OptionalHeader.Magic;
2023-09-13 00:08:11 -04:00
#else
public SabreTools.Models.PortableExecutable.OptionalHeaderMagicNumber? OH_Magic => _model.OptionalHeader?.Magic;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MajorLinkerVersion"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public byte OH_MajorLinkerVersion => _model.OptionalHeader.MajorLinkerVersion;
2023-09-13 00:08:11 -04:00
#else
public byte? OH_MajorLinkerVersion => _model.OptionalHeader?.MajorLinkerVersion;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MinorLinkerVersion"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public byte OH_MinorLinkerVersion => _model.OptionalHeader.MinorLinkerVersion;
2023-09-13 00:08:11 -04:00
#else
public byte? OH_MinorLinkerVersion => _model.OptionalHeader?.MinorLinkerVersion;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfCode"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_SizeOfCode => _model.OptionalHeader.SizeOfCode;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_SizeOfCode => _model.OptionalHeader?.SizeOfCode;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfInitializedData"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_SizeOfInitializedData => _model.OptionalHeader.SizeOfInitializedData;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_SizeOfInitializedData => _model.OptionalHeader?.SizeOfInitializedData;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfUninitializedData"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_SizeOfUninitializedData => _model.OptionalHeader.SizeOfUninitializedData;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_SizeOfUninitializedData => _model.OptionalHeader?.SizeOfUninitializedData;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.AddressOfEntryPoint"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_AddressOfEntryPoint => _model.OptionalHeader.AddressOfEntryPoint;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_AddressOfEntryPoint => _model.OptionalHeader?.AddressOfEntryPoint;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.BaseOfCode"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_BaseOfCode => _model.OptionalHeader.BaseOfCode;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_BaseOfCode => _model.OptionalHeader?.BaseOfCode;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.BaseOfData"/>
2023-09-13 00:08:11 -04:00
public uint? OH_BaseOfData => _model.OptionalHeader?.Magic == SabreTools.Models.PortableExecutable.OptionalHeaderMagicNumber.PE32
2023-09-11 23:25:09 -04:00
? (uint?)_model.OptionalHeader.BaseOfData
2022-12-02 16:16:12 -08:00
: null;
#endregion
#region Windows-Specific Fields
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ImageBase_PE32"/>
2023-09-13 00:08:11 -04:00
public ulong OH_ImageBase => _model.OptionalHeader?.Magic == SabreTools.Models.PortableExecutable.OptionalHeaderMagicNumber.PE32
2023-09-11 23:25:09 -04:00
? _model.OptionalHeader.ImageBase_PE32
2023-09-13 00:08:11 -04:00
: _model.OptionalHeader?.ImageBase_PE32Plus ?? 0;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SectionAlignment"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_SectionAlignment => _model.OptionalHeader.SectionAlignment;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_SectionAlignment => _model.OptionalHeader?.SectionAlignment;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.FileAlignment"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_FileAlignment => _model.OptionalHeader.FileAlignment;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_FileAlignment => _model.OptionalHeader?.FileAlignment;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MajorOperatingSystemVersion"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort OH_MajorOperatingSystemVersion => _model.OptionalHeader.MajorOperatingSystemVersion;
2023-09-13 00:08:11 -04:00
#else
public ushort? OH_MajorOperatingSystemVersion => _model.OptionalHeader?.MajorOperatingSystemVersion;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MinorOperatingSystemVersion"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort OH_MinorOperatingSystemVersion => _model.OptionalHeader.MinorOperatingSystemVersion;
2023-09-13 00:08:11 -04:00
#else
public ushort? OH_MinorOperatingSystemVersion => _model.OptionalHeader?.MinorOperatingSystemVersion;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MajorImageVersion"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort OH_MajorImageVersion => _model.OptionalHeader.MajorImageVersion;
2023-09-13 00:08:11 -04:00
#else
public ushort? OH_MajorImageVersion => _model.OptionalHeader?.MajorImageVersion;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MinorImageVersion"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort OH_MinorImageVersion => _model.OptionalHeader.MinorImageVersion;
2023-09-13 00:08:11 -04:00
#else
public ushort? OH_MinorImageVersion => _model.OptionalHeader?.MinorImageVersion;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MajorSubsystemVersion"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort OH_MajorSubsystemVersion => _model.OptionalHeader.MajorSubsystemVersion;
2023-09-13 00:08:11 -04:00
#else
public ushort? OH_MajorSubsystemVersion => _model.OptionalHeader?.MajorSubsystemVersion;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MinorSubsystemVersion"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ushort OH_MinorSubsystemVersion => _model.OptionalHeader.MinorSubsystemVersion;
2023-09-13 00:08:11 -04:00
#else
public ushort? OH_MinorSubsystemVersion => _model.OptionalHeader?.MinorSubsystemVersion;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Win32VersionValue"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_Win32VersionValue => _model.OptionalHeader.Win32VersionValue;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_Win32VersionValue => _model.OptionalHeader?.Win32VersionValue;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfImage"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_SizeOfImage => _model.OptionalHeader.SizeOfImage;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_SizeOfImage => _model.OptionalHeader?.SizeOfImage;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfHeaders"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_SizeOfHeaders => _model.OptionalHeader.SizeOfHeaders;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_SizeOfHeaders => _model.OptionalHeader?.SizeOfHeaders;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.CheckSum"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_CheckSum => _model.OptionalHeader.CheckSum;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_CheckSum => _model.OptionalHeader?.CheckSum;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Subsystem"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.WindowsSubsystem OH_Subsystem => _model.OptionalHeader.Subsystem;
2023-09-13 00:08:11 -04:00
#else
public SabreTools.Models.PortableExecutable.WindowsSubsystem? OH_Subsystem => _model.OptionalHeader?.Subsystem;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.DllCharacteristics"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DllCharacteristics OH_DllCharacteristics => _model.OptionalHeader.DllCharacteristics;
2023-09-13 00:08:11 -04:00
#else
public SabreTools.Models.PortableExecutable.DllCharacteristics? OH_DllCharacteristics => _model.OptionalHeader?.DllCharacteristics;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfStackReserve_PE32"/>
2023-09-13 00:08:11 -04:00
public ulong OH_SizeOfStackReserve => _model.OptionalHeader?.Magic == SabreTools.Models.PortableExecutable.OptionalHeaderMagicNumber.PE32
2023-09-11 23:25:09 -04:00
? _model.OptionalHeader.SizeOfStackReserve_PE32
2023-09-13 00:08:11 -04:00
: _model.OptionalHeader?.SizeOfStackReserve_PE32Plus ?? 0;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfStackCommit_PE32"/>
2023-09-13 00:08:11 -04:00
public ulong OH_SizeOfStackCommit => _model.OptionalHeader?.Magic == SabreTools.Models.PortableExecutable.OptionalHeaderMagicNumber.PE32
2023-09-11 23:25:09 -04:00
? _model.OptionalHeader.SizeOfStackCommit_PE32
2023-09-13 00:08:11 -04:00
: _model.OptionalHeader?.SizeOfStackCommit_PE32Plus ?? 0;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfHeapReserve_PE32"/>
2023-09-13 00:08:11 -04:00
public ulong OH_SizeOfHeapReserve => _model.OptionalHeader?.Magic == SabreTools.Models.PortableExecutable.OptionalHeaderMagicNumber.PE32
2023-09-11 23:25:09 -04:00
? _model.OptionalHeader.SizeOfHeapReserve_PE32
2023-09-13 00:08:11 -04:00
: _model.OptionalHeader?.SizeOfHeapReserve_PE32Plus ?? 0;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfHeapCommit_PE32"/>
2023-09-13 00:08:11 -04:00
public ulong OH_SizeOfHeapCommit => _model.OptionalHeader?.Magic == SabreTools.Models.PortableExecutable.OptionalHeaderMagicNumber.PE32
2023-09-11 23:25:09 -04:00
? _model.OptionalHeader.SizeOfHeapCommit_PE32
2023-09-13 00:08:11 -04:00
: _model.OptionalHeader?.SizeOfHeapCommit_PE32Plus ?? 0;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.LoaderFlags"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_LoaderFlags => _model.OptionalHeader.LoaderFlags;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_LoaderFlags => _model.OptionalHeader?.LoaderFlags;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.NumberOfRvaAndSizes"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public uint OH_NumberOfRvaAndSizes => _model.OptionalHeader.NumberOfRvaAndSizes;
2023-09-13 00:08:11 -04:00
#else
public uint? OH_NumberOfRvaAndSizes => _model.OptionalHeader?.NumberOfRvaAndSizes;
#endif
2022-12-02 16:16:12 -08:00
#endregion
#region Data Directories
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ExportTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_ExportTable => _model.OptionalHeader.ExportTable;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_ExportTable => _model.OptionalHeader?.ExportTable;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ImportTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_ImportTable => _model.OptionalHeader.ImportTable;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_ImportTable => _model.OptionalHeader?.ImportTable;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ResourceTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_ResourceTable => _model.OptionalHeader.ResourceTable;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_ResourceTable => _model.OptionalHeader?.ResourceTable;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ExceptionTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_ExceptionTable => _model.OptionalHeader.ExceptionTable;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_ExceptionTable => _model.OptionalHeader?.ExceptionTable;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.CertificateTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_CertificateTable => _model.OptionalHeader.CertificateTable;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_CertificateTable => _model.OptionalHeader?.CertificateTable;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.BaseRelocationTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_BaseRelocationTable => _model.OptionalHeader.BaseRelocationTable;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_BaseRelocationTable => _model.OptionalHeader?.BaseRelocationTable;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Debug"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_Debug => _model.OptionalHeader.Debug;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_Debug => _model.OptionalHeader?.Debug;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Architecture"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ulong OH_Architecture => _model.OptionalHeader.Architecture;
2023-09-13 00:08:11 -04:00
#else
public ulong? OH_Architecture => _model.OptionalHeader?.Architecture;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.GlobalPtr"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_GlobalPtr => _model.OptionalHeader.GlobalPtr;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_GlobalPtr => _model.OptionalHeader?.GlobalPtr;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ThreadLocalStorageTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_ThreadLocalStorageTable => _model.OptionalHeader.ThreadLocalStorageTable;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_ThreadLocalStorageTable => _model.OptionalHeader?.ThreadLocalStorageTable;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.LoadConfigTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_LoadConfigTable => _model.OptionalHeader.LoadConfigTable;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_LoadConfigTable => _model.OptionalHeader?.LoadConfigTable;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.BoundImport"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_BoundImport => _model.OptionalHeader.BoundImport;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_BoundImport => _model.OptionalHeader?.BoundImport;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ImportAddressTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_ImportAddressTable => _model.OptionalHeader.ImportAddressTable;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_ImportAddressTable => _model.OptionalHeader?.ImportAddressTable;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.DelayImportDescriptor"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_DelayImportDescriptor => _model.OptionalHeader.DelayImportDescriptor;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_DelayImportDescriptor => _model.OptionalHeader?.DelayImportDescriptor;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.CLRRuntimeHeader"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory OH_CLRRuntimeHeader => _model.OptionalHeader.CLRRuntimeHeader;
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:08:11 -04:00
public SabreTools.Models.PortableExecutable.DataDirectory? OH_CLRRuntimeHeader => _model.OptionalHeader?.CLRRuntimeHeader;
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Reserved"/>
2023-09-13 00:08:11 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public ulong OH_Reserved => _model.OptionalHeader.Reserved;
2023-09-13 00:08:11 -04:00
#else
public ulong? OH_Reserved => _model.OptionalHeader?.Reserved;
#endif
2022-12-02 16:16:12 -08:00
#endregion
#endregion
#region Tables
/// <inheritdoc cref="Models.PortableExecutable.SectionTable"/>
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.SectionHeader[] SectionTable => _model.SectionTable;
#else
public SabreTools.Models.PortableExecutable.SectionHeader?[]? SectionTable => _model.SectionTable;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFSymbolTable"/>
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.COFFSymbolTableEntry[] COFFSymbolTable => _model.COFFSymbolTable;
#else
public SabreTools.Models.PortableExecutable.COFFSymbolTableEntry?[]? COFFSymbolTable => _model.COFFSymbolTable;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFStringTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.COFFStringTable COFFStringTable => _model.COFFStringTable;
2023-09-12 17:12:23 -04:00
#else
public SabreTools.Models.PortableExecutable.COFFStringTable? COFFStringTable => _model.COFFStringTable;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.AttributeCertificateTable"/>
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.AttributeCertificateTableEntry[] AttributeCertificateTable => _model.AttributeCertificateTable;
#else
public SabreTools.Models.PortableExecutable.AttributeCertificateTableEntry?[]? AttributeCertificateTable => _model.AttributeCertificateTable;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.DelayLoadDirectoryTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DelayLoadDirectoryTable DelayLoadDirectoryTable => _model.DelayLoadDirectoryTable;
2023-09-12 17:12:23 -04:00
#else
public SabreTools.Models.PortableExecutable.DelayLoadDirectoryTable? DelayLoadDirectoryTable => _model.DelayLoadDirectoryTable;
#endif
2022-12-02 16:16:12 -08:00
#endregion
#region Sections
/// <inheritdoc cref="Models.PortableExecutable.BaseRelocationTable"/>
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.BaseRelocationBlock[] BaseRelocationTable => _model.BaseRelocationTable;
#else
public SabreTools.Models.PortableExecutable.BaseRelocationBlock?[]? BaseRelocationTable => _model.BaseRelocationTable;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.DebugTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.DebugTable DebugTable => _model.DebugTable;
2023-09-12 17:12:23 -04:00
#else
public SabreTools.Models.PortableExecutable.DebugTable? DebugTable => _model.DebugTable;
#endif
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.ExportTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.ExportTable ExportTable => _model.ExportTable;
2023-09-12 17:12:23 -04:00
#else
public SabreTools.Models.PortableExecutable.ExportTable? ExportTable => _model.ExportTable;
#endif
2022-12-02 16:16:12 -08:00
2022-12-02 22:24:22 -08:00
/// <inheritdoc cref="Models.PortableExecutable.ExportTable.ExportNameTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public string[] ExportNameTable => _model.ExportTable?.ExportNameTable?.Strings;
2023-09-12 17:12:23 -04:00
#else
public string[]? ExportNameTable => _model.ExportTable?.ExportNameTable?.Strings;
#endif
2022-12-02 22:24:22 -08:00
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.ImportTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.ImportTable ImportTable => _model.ImportTable;
2023-09-12 17:12:23 -04:00
#else
public SabreTools.Models.PortableExecutable.ImportTable? ImportTable => _model.ImportTable;
#endif
2022-12-02 16:16:12 -08:00
2022-12-02 22:24:22 -08:00
/// <inheritdoc cref="Models.PortableExecutable.ImportTable.HintNameTable"/>
#if NET48
2023-09-11 23:25:09 -04:00
public string[] ImportHintNameTable => _model.ImportTable?.HintNameTable != null
#else
public string?[]? ImportHintNameTable => _model.ImportTable?.HintNameTable != null
#endif
2023-09-13 00:08:11 -04:00
? _model.ImportTable.HintNameTable.Select(entry => entry?.Name).ToArray()
2022-12-02 22:24:22 -08:00
: null;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.ResourceDirectoryTable"/>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-11 23:25:09 -04:00
public SabreTools.Models.PortableExecutable.ResourceDirectoryTable ResourceDirectoryTable => _model.ResourceDirectoryTable;
2023-09-12 17:12:23 -04:00
#else
public SabreTools.Models.PortableExecutable.ResourceDirectoryTable? ResourceDirectoryTable => _model.ResourceDirectoryTable;
#endif
2022-12-02 16:16:12 -08:00
#endregion
2022-12-02 15:20:44 -08:00
#endregion
#region Extension Properties
2022-12-05 15:56:37 -08:00
/// <summary>
/// Header padding data, if it exists
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-05 15:56:37 -08:00
public byte[] HeaderPaddingData
2023-09-12 17:12:23 -04:00
#else
public byte[]? HeaderPaddingData
#endif
2022-12-05 15:56:37 -08:00
{
get
{
lock (_sourceDataLock)
{
2022-12-27 22:25:16 -08:00
// If we already have cached data, just use that immediately
if (_headerPaddingData != null)
return _headerPaddingData;
2022-12-05 15:56:37 -08:00
// TODO: Don't scan the known header data as well
2023-09-12 17:12:23 -04:00
// If the section table is missing
if (SectionTable == null)
return null;
2022-12-05 15:56:37 -08:00
// Populate the raw header padding data based on the source
2023-09-13 00:08:11 -04:00
#if NET48
2022-12-05 15:56:37 -08:00
uint headerStartAddress = Stub_NewExeHeaderAddr;
2023-09-13 00:08:11 -04:00
#else
uint headerStartAddress = Stub_NewExeHeaderAddr ?? 0;
#endif
uint firstSectionAddress = SectionTable
.Select(s => s?.PointerToRawData ?? 0)
.Where(s => s != 0)
.OrderBy(s => s)
.First();
2022-12-05 15:56:37 -08:00
int headerLength = (int)(firstSectionAddress - headerStartAddress);
_headerPaddingData = ReadFromDataSource((int)headerStartAddress, headerLength);
// Cache and return the header padding data, even if null
return _headerPaddingData;
}
}
}
2022-12-10 17:31:41 -08:00
/// <summary>
/// Header padding strings, if they exist
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-10 17:31:41 -08:00
public List<string> HeaderPaddingStrings
2023-09-12 17:12:23 -04:00
#else
public List<string>? HeaderPaddingStrings
#endif
2022-12-10 17:31:41 -08:00
{
get
{
lock (_sourceDataLock)
{
2022-12-27 22:25:16 -08:00
// If we already have cached data, just use that immediately
if (_headerPaddingStrings != null)
return _headerPaddingStrings;
2022-12-10 17:31:41 -08:00
// TODO: Don't scan the known header data as well
2023-09-12 17:12:23 -04:00
// If the section table is missing
if (SectionTable == null)
return null;
2022-12-10 17:31:41 -08:00
// Populate the raw header padding data based on the source
2023-09-13 00:08:11 -04:00
#if NET48
2022-12-10 17:31:41 -08:00
uint headerStartAddress = Stub_NewExeHeaderAddr;
2023-09-13 00:08:11 -04:00
#else
uint headerStartAddress = Stub_NewExeHeaderAddr ?? 0;
#endif
uint firstSectionAddress = SectionTable
.Select(s => s?.PointerToRawData ?? 0)
.Where(s => s != 0)
.OrderBy(s => s)
.First();
2022-12-10 17:31:41 -08:00
int headerLength = (int)(firstSectionAddress - headerStartAddress);
_headerPaddingStrings = ReadStringsFromDataSource((int)headerStartAddress, headerLength, charLimit: 3);
// Cache and return the header padding data, even if null
return _headerPaddingStrings;
}
}
}
2022-12-20 14:19:48 -08:00
/// <summary>
/// Entry point data, if it exists
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-20 14:19:48 -08:00
public byte[] EntryPointData
2023-09-12 17:12:23 -04:00
#else
public byte[]? EntryPointData
#endif
2022-12-20 14:19:48 -08:00
{
get
{
lock (_sourceDataLock)
{
2023-09-12 17:12:23 -04:00
// If the section table is missing
if (SectionTable == null)
return null;
2023-09-13 00:08:11 -04:00
#if NET6_0_OR_GREATER
// If the address is missing
if (OH_AddressOfEntryPoint == null)
return null;
#endif
2022-12-27 22:25:16 -08:00
// If we have no entry point
2023-09-13 00:08:11 -04:00
#if NET48
2022-12-27 22:25:16 -08:00
int entryPointAddress = (int)OH_AddressOfEntryPoint.ConvertVirtualAddress(SectionTable);
2023-09-13 00:08:11 -04:00
#else
int entryPointAddress = (int)OH_AddressOfEntryPoint.Value.ConvertVirtualAddress(SectionTable);
#endif
2022-12-27 22:25:16 -08:00
if (entryPointAddress == 0)
return null;
// If the entry point matches with the start of a section, use that
int entryPointSection = FindEntryPointSectionIndex();
2023-09-13 00:08:11 -04:00
if (entryPointSection >= 0 && OH_AddressOfEntryPoint == SectionTable[entryPointSection]?.VirtualAddress)
2022-12-27 22:25:16 -08:00
return GetSectionData(entryPointSection);
// If we already have cached data, just use that immediately
if (_entryPointData != null)
return _entryPointData;
2022-12-20 14:19:48 -08:00
// Read the first 128 bytes of the entry point
_entryPointData = ReadFromDataSource(entryPointAddress, length: 128);
// Cache and return the entry point padding data, even if null
return _entryPointData;
}
}
}
/// <summary>
/// Address of the overlay, if it exists
/// </summary>
/// <see href="https://www.autoitscript.com/forum/topic/153277-pe-file-overlay-extraction/"/>
public int OverlayAddress
{
get
{
lock (_sourceDataLock)
{
// Use the cached data if possible
if (_overlayAddress != null)
return _overlayAddress.Value;
// Get the end of the file, if possible
int endOfFile = GetEndOfFile();
if (endOfFile == -1)
return -1;
2023-09-12 17:12:23 -04:00
// If the section table is missing
if (SectionTable == null)
return -1;
// If we have certificate data, use that as the end
if (OH_CertificateTable != null)
{
2023-09-13 00:08:11 -04:00
int certificateTableAddress = (int)OH_CertificateTable.VirtualAddress.ConvertVirtualAddress(SectionTable);
if (certificateTableAddress != 0 && certificateTableAddress < endOfFile)
endOfFile = certificateTableAddress;
}
// Search through all sections and find the furthest a section goes
int endOfSectionData = -1;
2023-09-13 00:08:11 -04:00
foreach (var section in SectionTable)
{
2023-09-13 00:08:11 -04:00
// If we have an invalid section
if (section == null)
continue;
// If we have an invalid section address
2023-09-13 00:08:11 -04:00
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(SectionTable);
if (sectionAddress == 0)
continue;
// If we have an invalid section size
if (section.SizeOfRawData == 0 && section.VirtualSize == 0)
continue;
// Get the real section size
int sectionSize;
if (section.SizeOfRawData < section.VirtualSize)
sectionSize = (int)section.VirtualSize;
else
sectionSize = (int)section.SizeOfRawData;
// Compare and set the end of section data
if (sectionAddress + sectionSize > endOfSectionData)
endOfSectionData = sectionAddress + sectionSize;
}
// If we didn't find the end of section data
if (endOfSectionData <= 0)
endOfSectionData = -1;
// Cache and return the position
_overlayAddress = endOfSectionData;
return _overlayAddress.Value;
}
}
}
2022-12-02 21:20:52 -08:00
/// <summary>
/// Overlay data, if it exists
/// </summary>
2022-12-02 22:44:55 -08:00
/// <see href="https://www.autoitscript.com/forum/topic/153277-pe-file-overlay-extraction/"/>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-10 20:10:25 -08:00
public byte[] OverlayData
2023-09-12 17:12:23 -04:00
#else
public byte[]? OverlayData
#endif
2022-12-02 21:20:52 -08:00
{
get
{
2022-12-20 14:19:48 -08:00
lock (_sourceDataLock)
{
2022-12-27 22:25:16 -08:00
// Use the cached data if possible
if (_overlayData != null)
return _overlayData;
// Get the end of the file, if possible
int endOfFile = GetEndOfFile();
if (endOfFile == -1)
return null;
2023-09-12 17:12:23 -04:00
// If the section table is missing
if (SectionTable == null)
return null;
2022-12-02 22:44:55 -08:00
// If we have certificate data, use that as the end
2022-12-05 11:01:22 -08:00
if (OH_CertificateTable != null)
2022-12-02 22:44:55 -08:00
{
2023-09-13 00:08:11 -04:00
int certificateTableAddress = (int)OH_CertificateTable.VirtualAddress.ConvertVirtualAddress(SectionTable);
2022-12-03 21:59:21 -08:00
if (certificateTableAddress != 0 && certificateTableAddress < endOfFile)
2022-12-02 22:44:55 -08:00
endOfFile = certificateTableAddress;
}
// Search through all sections and find the furthest a section goes
int endOfSectionData = -1;
2023-09-13 00:08:11 -04:00
foreach (var section in SectionTable)
2022-12-02 22:44:55 -08:00
{
2023-09-13 00:08:11 -04:00
// If we have an invalid section
if (section == null)
continue;
2022-12-02 22:44:55 -08:00
// If we have an invalid section address
2023-09-13 00:08:11 -04:00
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(SectionTable);
2022-12-02 22:44:55 -08:00
if (sectionAddress == 0)
continue;
// If we have an invalid section size
if (section.SizeOfRawData == 0 && section.VirtualSize == 0)
continue;
// Get the real section size
int sectionSize;
if (section.SizeOfRawData < section.VirtualSize)
sectionSize = (int)section.VirtualSize;
else
sectionSize = (int)section.SizeOfRawData;
// Compare and set the end of section data
if (sectionAddress + sectionSize > endOfSectionData)
endOfSectionData = sectionAddress + sectionSize;
}
// If we didn't find the end of section data
if (endOfSectionData <= 0)
return null;
// If we're at the end of the file, cache an empty byte array
2022-12-03 21:59:21 -08:00
if (endOfSectionData >= endOfFile)
2022-12-02 22:44:55 -08:00
{
_overlayData = new byte[0];
return _overlayData;
}
// Otherwise, cache and return the data
int overlayLength = endOfFile - endOfSectionData;
_overlayData = ReadFromDataSource(endOfSectionData, overlayLength);
return _overlayData;
2022-12-02 21:20:52 -08:00
}
}
}
2022-12-10 20:10:25 -08:00
/// <summary>
/// Overlay strings, if they exist
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-10 20:10:25 -08:00
public List<string> OverlayStrings
2023-09-12 17:12:23 -04:00
#else
public List<string>? OverlayStrings
#endif
2022-12-10 20:10:25 -08:00
{
get
{
2022-12-20 14:19:48 -08:00
lock (_sourceDataLock)
{
2022-12-27 22:25:16 -08:00
// Use the cached data if possible
if (_overlayStrings != null)
return _overlayStrings;
// Get the end of the file, if possible
int endOfFile = GetEndOfFile();
if (endOfFile == -1)
return null;
2023-09-12 17:12:23 -04:00
// If the section table is missing
if (SectionTable == null)
return null;
2022-12-10 20:10:25 -08:00
// If we have certificate data, use that as the end
if (OH_CertificateTable != null)
{
2023-09-13 00:08:11 -04:00
var certificateTable = OH_CertificateTable;
2023-09-12 17:12:23 -04:00
int certificateTableAddress = (int)certificateTable.VirtualAddress.ConvertVirtualAddress(SectionTable);
2022-12-10 20:10:25 -08:00
if (certificateTableAddress != 0 && certificateTableAddress < endOfFile)
endOfFile = certificateTableAddress;
}
// Search through all sections and find the furthest a section goes
int endOfSectionData = -1;
2023-09-13 00:08:11 -04:00
foreach (var section in SectionTable)
2022-12-10 20:10:25 -08:00
{
2023-09-13 00:08:11 -04:00
// If we have an invalid section
if (section == null)
continue;
2022-12-10 20:10:25 -08:00
// If we have an invalid section address
2023-09-13 00:08:11 -04:00
int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(SectionTable);
2022-12-10 20:10:25 -08:00
if (sectionAddress == 0)
continue;
// If we have an invalid section size
if (section.SizeOfRawData == 0 && section.VirtualSize == 0)
continue;
// Get the real section size
int sectionSize;
if (section.SizeOfRawData < section.VirtualSize)
sectionSize = (int)section.VirtualSize;
else
sectionSize = (int)section.SizeOfRawData;
// Compare and set the end of section data
if (sectionAddress + sectionSize > endOfSectionData)
endOfSectionData = sectionAddress + sectionSize;
}
// If we didn't find the end of section data
if (endOfSectionData <= 0)
return null;
// If we're at the end of the file, cache an empty list
if (endOfSectionData >= endOfFile)
{
_overlayStrings = new List<string>();
return _overlayStrings;
}
// Otherwise, cache and return the strings
int overlayLength = endOfFile - endOfSectionData;
_overlayStrings = ReadStringsFromDataSource(endOfSectionData, overlayLength, charLimit: 3);
return _overlayStrings;
}
}
}
/// <summary>
2022-12-03 20:56:06 -08:00
/// Sanitized section names
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
public string[] SectionNames
2023-09-12 17:12:23 -04:00
#else
public string[]? SectionNames
#endif
{
get
{
lock (_sourceDataLock)
2022-12-20 14:19:48 -08:00
{
// Use the cached data if possible
if (_sectionNames != null)
return _sectionNames;
2023-09-13 00:08:11 -04:00
// If there are no sections
if (SectionTable == null)
return null;
// Otherwise, build and return the cached array
2023-09-13 00:08:11 -04:00
_sectionNames = new string[SectionTable.Length];
for (int i = 0; i < _sectionNames.Length; i++)
{
2023-09-13 00:08:11 -04:00
var section = SectionTable[i];
if (section == null)
continue;
// TODO: Handle long section names with leading `/`
2023-09-12 17:12:23 -04:00
#if NET48
byte[] sectionNameBytes = section.Name;
2023-09-12 17:12:23 -04:00
#else
byte[]? sectionNameBytes = section.Name;
#endif
if (sectionNameBytes != null)
{
string sectionNameString = Encoding.UTF8.GetString(sectionNameBytes).TrimEnd('\0');
_sectionNames[i] = sectionNameString;
}
}
2022-12-20 14:19:48 -08:00
return _sectionNames;
}
}
}
2022-12-03 20:56:06 -08:00
/// <summary>
/// Stub executable data, if it exists
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
public byte[] StubExecutableData
2023-09-12 17:12:23 -04:00
#else
public byte[]? StubExecutableData
#endif
2022-12-03 20:56:06 -08:00
{
get
{
lock (_sourceDataLock)
2022-12-03 20:56:06 -08:00
{
2022-12-27 22:25:16 -08:00
// If we already have cached data, just use that immediately
if (_stubExecutableData != null)
return _stubExecutableData;
2023-09-13 00:29:21 -04:00
#if NET6_0_OR_GREATER
if (Stub_NewExeHeaderAddr == null)
return null;
#endif
2022-12-03 20:56:06 -08:00
// Populate the raw stub executable data based on the source
int endOfStubHeader = 0x40;
2023-09-13 00:08:11 -04:00
int lengthOfStubExecutableData = (int)Stub_NewExeHeaderAddr - endOfStubHeader;
2022-12-03 20:56:06 -08:00
_stubExecutableData = ReadFromDataSource(endOfStubHeader, lengthOfStubExecutableData);
// Cache and return the stub executable data, even if null
return _stubExecutableData;
}
}
}
2022-12-14 20:46:24 -08:00
/// <summary>
/// Dictionary of debug data
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-14 21:07:02 -08:00
public Dictionary<int, object> DebugData
2023-09-12 17:12:23 -04:00
#else
public Dictionary<int, object>? DebugData
#endif
2022-12-14 20:46:24 -08:00
{
get
{
2022-12-20 14:19:48 -08:00
lock (_sourceDataLock)
{
2022-12-27 22:25:16 -08:00
// Use the cached data if possible
if (_debugData != null && _debugData.Count != 0)
return _debugData;
// If we have no resource table, just return
if (DebugTable?.DebugDirectoryTable == null
|| DebugTable.DebugDirectoryTable.Length == 0)
return null;
2022-12-20 14:19:48 -08:00
// Otherwise, build and return the cached dictionary
ParseDebugTable();
return _debugData;
}
2022-12-14 20:46:24 -08:00
}
}
2022-12-02 22:24:22 -08:00
/// <summary>
/// Dictionary of resource data
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-02 22:24:22 -08:00
public Dictionary<string, object> ResourceData
2023-09-12 17:12:23 -04:00
#else
2023-09-13 00:29:21 -04:00
public Dictionary<string, object?>? ResourceData
2023-09-12 17:12:23 -04:00
#endif
2022-12-02 22:24:22 -08:00
{
get
{
2022-12-20 14:19:48 -08:00
lock (_sourceDataLock)
{
2022-12-27 22:25:16 -08:00
// Use the cached data if possible
if (_resourceData != null && _resourceData.Count != 0)
return _resourceData;
// If we have no resource table, just return
if (OH_ResourceTable == null
|| OH_ResourceTable.VirtualAddress == 0
|| ResourceDirectoryTable == null)
return null;
2022-12-02 22:24:22 -08:00
// Otherwise, build and return the cached dictionary
2022-12-14 20:46:24 -08:00
ParseResourceDirectoryTable(ResourceDirectoryTable, types: new List<object>());
2022-12-02 22:24:22 -08:00
return _resourceData;
}
}
}
#region Version Information
2022-12-08 14:40:30 -08:00
/// <summary>
/// "Build GUID"
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-08 14:40:30 -08:00
public string BuildGuid => GetVersionInfoString("BuildGuid");
2023-09-12 17:12:23 -04:00
#else
public string? BuildGuid => GetVersionInfoString("BuildGuid");
#endif
2022-12-08 14:40:30 -08:00
/// <summary>
/// "Build signature"
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-08 14:40:30 -08:00
public string BuildSignature => GetVersionInfoString("BuildSignature");
2023-09-12 17:12:23 -04:00
#else
public string? BuildSignature => GetVersionInfoString("BuildSignature");
#endif
2022-12-14 17:24:14 -08:00
2022-12-02 22:24:22 -08:00
/// <summary>
/// Additional information that should be displayed for diagnostic purposes.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string Comments => GetVersionInfoString("Comments");
2023-09-12 17:12:23 -04:00
#else
public string? Comments => GetVersionInfoString("Comments");
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Company that produced the file—for example, "Microsoft Corporation" or
/// "Standard Microsystems Corporation, Inc." This string is required.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string CompanyName => GetVersionInfoString("CompanyName");
2023-09-12 17:12:23 -04:00
#else
public string? CompanyName => GetVersionInfoString("CompanyName");
#endif
2022-12-02 22:24:22 -08:00
2022-12-08 14:59:15 -08:00
/// <summary>
/// "Debug version"
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-08 14:59:15 -08:00
public string DebugVersion => GetVersionInfoString("DebugVersion");
2023-09-12 17:12:23 -04:00
#else
public string? DebugVersion => GetVersionInfoString("DebugVersion");
#endif
2022-12-08 14:59:15 -08:00
2022-12-02 22:24:22 -08:00
/// <summary>
/// File description to be presented to users. This string may be displayed in a
/// list box when the user is choosing files to install—for example, "Keyboard
/// Driver for AT-Style Keyboards". This string is required.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string FileDescription => GetVersionInfoString("FileDescription");
2023-09-12 17:12:23 -04:00
#else
public string? FileDescription => GetVersionInfoString("FileDescription");
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Version number of the file—for example, "3.10" or "5.00.RC2". This string
/// is required.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string FileVersion => GetVersionInfoString("FileVersion");
2023-09-12 17:12:23 -04:00
#else
public string? FileVersion => GetVersionInfoString("FileVersion");
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Internal name of the file, if one exists—for example, a module name if the
/// file is a dynamic-link library. If the file has no internal name, this
/// string should be the original filename, without extension. This string is required.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string InternalName => GetVersionInfoString(key: "InternalName");
2023-09-12 17:12:23 -04:00
#else
public string? InternalName => GetVersionInfoString(key: "InternalName");
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Copyright notices that apply to the file. This should include the full text of
/// all notices, legal symbols, copyright dates, and so on. This string is optional.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string LegalCopyright => GetVersionInfoString(key: "LegalCopyright");
2023-09-12 17:12:23 -04:00
#else
public string? LegalCopyright => GetVersionInfoString(key: "LegalCopyright");
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Trademarks and registered trademarks that apply to the file. This should include
/// the full text of all notices, legal symbols, trademark numbers, and so on. This
/// string is optional.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string LegalTrademarks => GetVersionInfoString(key: "LegalTrademarks");
2023-09-12 17:12:23 -04:00
#else
public string? LegalTrademarks => GetVersionInfoString(key: "LegalTrademarks");
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Original name of the file, not including a path. This information enables an
/// application to determine whether a file has been renamed by a user. The format of
/// the name depends on the file system for which the file was created. This string
/// is required.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string OriginalFilename => GetVersionInfoString(key: "OriginalFilename");
2023-09-12 17:12:23 -04:00
#else
public string? OriginalFilename => GetVersionInfoString(key: "OriginalFilename");
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Information about a private version of the file—for example, "Built by TESTER1 on
/// \TESTBED". This string should be present only if VS_FF_PRIVATEBUILD is specified in
/// the fileflags parameter of the root block.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string PrivateBuild => GetVersionInfoString(key: "PrivateBuild");
2023-09-12 17:12:23 -04:00
#else
public string? PrivateBuild => GetVersionInfoString(key: "PrivateBuild");
#endif
2022-12-02 22:24:22 -08:00
2022-12-08 14:40:30 -08:00
/// <summary>
/// "Product GUID"
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-08 14:40:30 -08:00
public string ProductGuid => GetVersionInfoString("ProductGuid");
2023-09-12 17:12:23 -04:00
#else
public string? ProductGuid => GetVersionInfoString("ProductGuid");
#endif
2022-12-08 14:40:30 -08:00
2022-12-02 22:24:22 -08:00
/// <summary>
/// Name of the product with which the file is distributed. This string is required.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string ProductName => GetVersionInfoString(key: "ProductName");
2023-09-12 17:12:23 -04:00
#else
public string? ProductName => GetVersionInfoString(key: "ProductName");
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Version of the product with which the file is distributed—for example, "3.10" or
/// "5.00.RC2". This string is required.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-02 22:24:22 -08:00
public string ProductVersion => GetVersionInfoString(key: "ProductVersion");
2023-09-12 17:12:23 -04:00
#else
public string? ProductVersion => GetVersionInfoString(key: "ProductVersion");
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Text that specifies how this version of the file differs from the standard
/// version—for example, "Private build for TESTER1 solving mouse problems on M250 and
/// M250E computers". This string should be present only if VS_FF_SPECIALBUILD is
/// specified in the fileflags parameter of the root block.
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-08 14:59:15 -08:00
public string SpecialBuild => GetVersionInfoString(key: "SpecialBuild") ?? GetVersionInfoString(key: "Special Build");
2023-09-12 17:12:23 -04:00
#else
public string? SpecialBuild => GetVersionInfoString(key: "SpecialBuild") ?? GetVersionInfoString(key: "Special Build");
#endif
2022-12-02 22:24:22 -08:00
2022-12-08 14:40:30 -08:00
/// <summary>
/// "Trade name"
2023-09-12 17:12:23 -04:00
/// </summary/>
#if NET48
2022-12-08 14:40:30 -08:00
public string TradeName => GetVersionInfoString(key: "TradeName");
2023-09-12 17:12:23 -04:00
#else
public string? TradeName => GetVersionInfoString(key: "TradeName");
#endif
2022-12-08 14:40:30 -08:00
/// <summary>
/// Get the internal version as reported by the resources
/// </summary>
/// <returns>Version string, null on error</returns>
/// <remarks>The internal version is either the file version, product version, or assembly version, in that order</remarks>
2023-09-12 17:12:23 -04:00
#if NET48
public string GetInternalVersion()
2023-09-12 17:12:23 -04:00
#else
public string? GetInternalVersion()
#endif
{
2023-09-12 17:12:23 -04:00
#if NET48
string version = this.FileVersion;
2023-09-12 17:12:23 -04:00
#else
string? version = this.FileVersion;
#endif
if (!string.IsNullOrWhiteSpace(version))
return version.Replace(", ", ".");
version = this.ProductVersion;
if (!string.IsNullOrWhiteSpace(version))
return version.Replace(", ", ".");
version = this.AssemblyVersion;
if (!string.IsNullOrWhiteSpace(version))
return version;
return null;
}
2022-12-02 22:24:22 -08:00
#endregion
#region Manifest Information
/// <summary>
/// Description as derived from the assembly manifest
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-02 22:24:22 -08:00
public string AssemblyDescription
2023-09-12 17:12:23 -04:00
#else
public string? AssemblyDescription
#endif
2022-12-02 22:24:22 -08:00
{
get
{
var manifest = GetAssemblyManifest();
return manifest?
.Description?
.Value;
}
}
/// <summary>
/// Version as derived from the assembly manifest
/// </summary>
/// <remarks>
/// If there are multiple identities included in the manifest,
/// this will only retrieve the value from the first that doesn't
/// have a null or empty version.
/// </remarks>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-02 22:24:22 -08:00
public string AssemblyVersion
2023-09-12 17:12:23 -04:00
#else
public string? AssemblyVersion
#endif
2022-12-02 22:24:22 -08:00
{
get
{
var manifest = GetAssemblyManifest();
return manifest?
.AssemblyIdentities?
2023-09-13 00:08:11 -04:00
.FirstOrDefault(ai => !string.IsNullOrWhiteSpace(ai?.Version))?
2022-12-02 22:24:22 -08:00
.Version;
}
}
#endregion
2022-12-02 15:20:44 -08:00
#endregion
#region Instance Variables
2022-12-05 15:56:37 -08:00
/// <summary>
/// Header padding data, if it exists
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-05 15:56:37 -08:00
private byte[] _headerPaddingData = null;
2023-09-12 17:12:23 -04:00
#else
private byte[]? _headerPaddingData = null;
#endif
2022-12-05 15:56:37 -08:00
2022-12-10 17:31:41 -08:00
/// <summary>
2022-12-10 20:10:25 -08:00
/// Header padding strings, if they exist
2022-12-10 17:31:41 -08:00
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-10 17:31:41 -08:00
private List<string> _headerPaddingStrings = null;
2023-09-12 17:12:23 -04:00
#else
private List<string>? _headerPaddingStrings = null;
#endif
2022-12-10 17:31:41 -08:00
2022-12-20 14:19:48 -08:00
/// <summary>
/// Entry point data, if it exists and isn't aligned to a section
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-20 14:19:48 -08:00
private byte[] _entryPointData = null;
2023-09-12 17:12:23 -04:00
#else
private byte[]? _entryPointData = null;
#endif
2022-12-20 14:19:48 -08:00
/// <summary>
/// Address of the overlay, if it exists
/// </summary>
private int? _overlayAddress = null;
/// <summary>
2022-12-02 21:20:52 -08:00
/// Overlay data, if it exists
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-02 21:20:52 -08:00
private byte[] _overlayData = null;
2023-09-12 17:12:23 -04:00
#else
private byte[]? _overlayData = null;
#endif
2022-12-10 20:10:25 -08:00
/// <summary>
/// Overlay strings, if they exist
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-10 20:10:25 -08:00
private List<string> _overlayStrings = null;
2023-09-12 17:12:23 -04:00
#else
private List<string>? _overlayStrings = null;
#endif
2022-12-10 20:10:25 -08:00
/// <summary>
2022-12-03 20:56:06 -08:00
/// Stub executable data, if it exists
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
private byte[] _stubExecutableData = null;
2023-09-12 17:12:23 -04:00
#else
private byte[]? _stubExecutableData = null;
#endif
2022-12-03 20:56:06 -08:00
/// <summary>
/// Sanitized section names
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-02 21:20:52 -08:00
private string[] _sectionNames = null;
2023-09-12 17:12:23 -04:00
#else
private string[]? _sectionNames = null;
#endif
/// <summary>
/// Cached raw section data
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
private byte[][] _sectionData = null;
2023-09-12 17:12:23 -04:00
#else
private byte[]?[]? _sectionData = null;
#endif
2022-12-05 11:01:22 -08:00
2022-12-09 11:53:58 -08:00
/// <summary>
/// Cached found string data in sections
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-09 11:53:58 -08:00
private List<string>[] _sectionStringData = null;
2023-09-12 17:12:23 -04:00
#else
private List<string>?[]? _sectionStringData = null;
#endif
2022-12-09 11:53:58 -08:00
2022-12-14 17:24:14 -08:00
/// <summary>
/// Cached raw table data
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-14 17:24:14 -08:00
private byte[][] _tableData = null;
2023-09-12 17:12:23 -04:00
#else
private byte[]?[]? _tableData = null;
#endif
2022-12-14 17:24:14 -08:00
/// <summary>
/// Cached found string data in tables
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-14 17:24:14 -08:00
private List<string>[] _tableStringData = null;
2023-09-12 17:12:23 -04:00
#else
private List<string>?[]? _tableStringData = null;
#endif
2022-12-14 17:24:14 -08:00
2022-12-14 20:46:24 -08:00
/// <summary>
/// Cached debug data
/// </summary>
2022-12-14 21:07:02 -08:00
private readonly Dictionary<int, object> _debugData = new Dictionary<int, object>();
2022-12-14 20:46:24 -08:00
2022-12-02 22:24:22 -08:00
/// <summary>
/// Cached resource data
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-02 22:24:22 -08:00
private readonly Dictionary<string, object> _resourceData = new Dictionary<string, object>();
2023-09-12 17:12:23 -04:00
#else
private readonly Dictionary<string, object?> _resourceData = new Dictionary<string, object?>();
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Cached version info data
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-04 23:44:45 -04:00
private SabreTools.Models.PortableExecutable.VersionInfo _versionInfo = null;
2023-09-12 17:12:23 -04:00
#else
private SabreTools.Models.PortableExecutable.VersionInfo? _versionInfo = null;
#endif
2022-12-02 22:24:22 -08:00
/// <summary>
/// Cached assembly manifest data
/// </summary>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-04 23:44:45 -04:00
private SabreTools.Models.PortableExecutable.AssemblyManifest _assemblyManifest = null;
2023-09-12 17:12:23 -04:00
#else
private SabreTools.Models.PortableExecutable.AssemblyManifest? _assemblyManifest = null;
#endif
2022-12-02 22:24:22 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Lock object for reading from the source
2022-12-02 21:20:52 -08:00
/// </summary>
private readonly object _sourceDataLock = new object();
2022-12-02 22:24:22 -08:00
2022-12-02 21:20:52 -08:00
#endregion
#region Constructors
2023-09-11 23:25:09 -04:00
/// <inheritdoc/>
#if NET48
public PortableExecutable(SabreTools.Models.PortableExecutable.Executable model, byte[] data, int offset)
#else
public PortableExecutable(SabreTools.Models.PortableExecutable.Executable? model, byte[]? data, int offset)
#endif
: base(model, data, offset)
{
// All logic is handled by the base class
}
/// <inheritdoc/>
#if NET48
public PortableExecutable(SabreTools.Models.PortableExecutable.Executable model, Stream data)
#else
public PortableExecutable(SabreTools.Models.PortableExecutable.Executable? model, Stream? data)
#endif
: base(model, data)
{
// All logic is handled by the base class
}
2022-12-02 15:20:44 -08:00
/// <summary>
/// Create a PE executable from a byte array and offset
/// </summary>
/// <param name="data">Byte array representing the executable</param>
/// <param name="offset">Offset within the array to parse</param>
/// <returns>A PE executable wrapper on success, null on failure</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-02 15:20:44 -08:00
public static PortableExecutable Create(byte[] data, int offset)
2023-09-12 17:12:23 -04:00
#else
public static PortableExecutable? Create(byte[]? data, int offset)
#endif
2022-12-02 15:20:44 -08:00
{
2022-12-15 14:20:27 -08:00
// 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);
2022-12-15 12:41:08 -08:00
return Create(dataStream);
2022-12-02 15:20:44 -08:00
}
/// <summary>
/// Create a PE executable from a Stream
/// </summary>
/// <param name="data">Stream representing the executable</param>
/// <returns>A PE executable wrapper on success, null on failure</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-02 15:20:44 -08:00
public static PortableExecutable Create(Stream data)
2023-09-12 17:12:23 -04:00
#else
public static PortableExecutable? Create(Stream? data)
#endif
2022-12-02 15:20:44 -08:00
{
2022-12-15 14:20:27 -08:00
// If the data is invalid
if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead)
return null;
2023-09-10 23:51:38 -04:00
var executable = new SabreTools.Serialization.Streams.PortableExecutable().Deserialize(data);
2022-12-02 15:20:44 -08:00
if (executable == null)
return null;
2023-09-11 23:25:09 -04:00
try
{
2023-09-11 23:25:09 -04:00
return new PortableExecutable(executable, data);
}
catch
{
return null;
}
2022-12-02 15:20:44 -08:00
}
2022-12-02 21:20:52 -08:00
#endregion
2022-12-02 22:24:22 -08:00
#region Data
2022-12-02 21:20:52 -08:00
// TODO: Cache all certificate objects
2022-12-02 22:24:22 -08:00
/// <summary>
/// Get the version info string associated with a key, if possible
/// </summary>
/// <param name="key">Case-insensitive key to find in the version info</param>
/// <returns>String representing the data, null on error</returns>
/// <remarks>
/// This code does not take into account the locale and will find and return
/// the first available value. This may not actually matter for version info,
/// but it is worth mentioning.
/// </remarks>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-02 22:24:22 -08:00
public string GetVersionInfoString(string key)
2023-09-12 17:12:23 -04:00
#else
public string? GetVersionInfoString(string key)
#endif
2022-12-02 22:24:22 -08:00
{
// If we have an invalid key, we can't do anything
if (string.IsNullOrEmpty(key))
return null;
// Ensure that we have the resource data cached
if (ResourceData == null)
return null;
2022-12-02 22:24:22 -08:00
// If we don't have string version info in this executable
var stringTable = _versionInfo?.StringFileInfo?.Children;
if (stringTable == null || !stringTable.Any())
return null;
// Try to find a key that matches
var match = stringTable
2023-09-12 17:12:23 -04:00
.SelectMany(st => st?.Children ?? Array.Empty<SabreTools.Models.PortableExecutable.StringData>())
.FirstOrDefault(sd => sd != null && key.Equals(sd.Key, StringComparison.OrdinalIgnoreCase));
2022-12-02 22:24:22 -08:00
// Return either the match or null
return match?.Value?.TrimEnd('\0');
}
/// <summary>
/// Get the assembly manifest, if possible
/// </summary>
/// <returns>Assembly manifest object, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-04 23:44:45 -04:00
private SabreTools.Models.PortableExecutable.AssemblyManifest GetAssemblyManifest()
2023-09-12 17:12:23 -04:00
#else
private SabreTools.Models.PortableExecutable.AssemblyManifest? GetAssemblyManifest()
#endif
2022-12-02 22:24:22 -08:00
{
// Use the cached data if possible
if (_assemblyManifest != null)
return _assemblyManifest;
// Ensure that we have the resource data cached
if (ResourceData == null)
return null;
2022-12-02 22:24:22 -08:00
// Return the now-cached assembly manifest
return _assemblyManifest;
}
#endregion
2022-12-02 20:09:55 -08:00
#region Printing
2022-12-02 21:20:52 -08:00
/// <inheritdoc/>
2023-01-13 14:04:21 -08:00
public override StringBuilder PrettyPrint()
{
2023-01-13 14:04:21 -08:00
StringBuilder builder = new StringBuilder();
2023-09-15 02:37:45 -04:00
Printing.PortableExecutable.Print(builder, _model);
2023-01-13 14:04:21 -08:00
return builder;
2022-12-02 21:20:52 -08:00
}
#if NET6_0_OR_GREATER
/// <inheritdoc/>
2023-09-11 23:25:09 -04:00
public override string ExportJSON() => System.Text.Json.JsonSerializer.Serialize(_model, _jsonSerializerOptions);
#endif
2022-12-02 20:09:55 -08:00
#endregion
2022-12-03 14:22:54 -08:00
2022-12-14 20:46:24 -08:00
#region Debug Data
2022-12-14 21:07:02 -08:00
/// <summary>
/// Find CodeView debug data by path
/// </summary>
/// <param name="path">Partial path to check for</param>
/// <returns>Enumerable of matching debug data</returns>
#if NET48
2022-12-14 21:07:02 -08:00
public IEnumerable<object> FindCodeViewDebugTableByPath(string path)
#else
public IEnumerable<object?> FindCodeViewDebugTableByPath(string path)
#endif
2022-12-14 21:07:02 -08:00
{
// Ensure that we have the debug data cached
if (DebugData == null)
#if NET48
2022-12-14 21:07:02 -08:00
return Enumerable.Empty<object>();
#else
return Enumerable.Empty<object?>();
#endif
2022-12-14 21:07:02 -08:00
2022-12-14 21:30:53 -08:00
var nb10Found = DebugData.Select(r => r.Value)
2023-09-04 23:44:45 -04:00
.Select(r => r as SabreTools.Models.PortableExecutable.NB10ProgramDatabase)
2022-12-14 21:07:02 -08:00
.Where(n => n != null)
2023-09-13 00:08:11 -04:00
.Where(n => n?.PdbFileName?.Contains(path) == true)
.Select(n => n as object);
2022-12-14 21:30:53 -08:00
var rsdsFound = DebugData.Select(r => r.Value)
2023-09-04 23:44:45 -04:00
.Select(r => r as SabreTools.Models.PortableExecutable.RSDSProgramDatabase)
2022-12-14 21:30:53 -08:00
.Where(r => r != null)
2023-09-13 00:08:11 -04:00
.Where(r => r?.PathAndFileName?.Contains(path) == true)
.Select(r => r as object);
2022-12-14 21:30:53 -08:00
return nb10Found.Concat(rsdsFound);
2022-12-14 21:07:02 -08:00
}
2022-12-14 20:46:24 -08:00
/// <summary>
/// Find unparsed debug data by string value
/// </summary>
/// <param name="value">String value to check for</param>
/// <returns>Enumerable of matching debug data</returns>
#if NET48
2022-12-14 21:07:02 -08:00
public IEnumerable<byte[]> FindGenericDebugTableByValue(string value)
#else
public IEnumerable<byte[]?> FindGenericDebugTableByValue(string value)
#endif
2022-12-14 20:46:24 -08:00
{
// Ensure that we have the resource data cached
if (DebugData == null)
#if NET48
2022-12-14 20:46:24 -08:00
return Enumerable.Empty<byte[]>();
#else
return Enumerable.Empty<byte[]>();
#endif
2022-12-14 20:46:24 -08:00
return DebugData.Select(r => r.Value)
2022-12-14 21:07:02 -08:00
.Select(b => b as byte[])
2022-12-14 20:46:24 -08:00
.Where(b => b != null)
.Where(b =>
{
try
{
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-14 20:46:24 -08:00
string arrayAsASCII = Encoding.ASCII.GetString(b);
2023-09-12 17:12:23 -04:00
#else
string? arrayAsASCII = Encoding.ASCII.GetString(b!);
#endif
2022-12-14 20:46:24 -08:00
if (arrayAsASCII.Contains(value))
return true;
}
catch { }
try
{
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-14 20:46:24 -08:00
string arrayAsUTF8 = Encoding.UTF8.GetString(b);
2023-09-12 17:12:23 -04:00
#else
string? arrayAsUTF8 = Encoding.UTF8.GetString(b!);
#endif
2022-12-14 20:46:24 -08:00
if (arrayAsUTF8.Contains(value))
return true;
}
catch { }
try
{
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-14 20:46:24 -08:00
string arrayAsUnicode = Encoding.Unicode.GetString(b);
2023-09-12 17:12:23 -04:00
#else
string? arrayAsUnicode = Encoding.Unicode.GetString(b!);
#endif
2022-12-14 20:46:24 -08:00
if (arrayAsUnicode.Contains(value))
return true;
}
catch { }
return false;
});
}
#endregion
#region Debug Parsing
/// <summary>
/// Parse the debug directory table information
/// </summary>
private void ParseDebugTable()
{
2023-09-13 00:08:11 -04:00
// If there is no debug table
if (DebugTable?.DebugDirectoryTable == null)
return;
2022-12-14 20:46:24 -08:00
// Loop through all debug table entries
for (int i = 0; i < DebugTable.DebugDirectoryTable.Length; i++)
{
var entry = DebugTable.DebugDirectoryTable[i];
2023-09-13 00:08:11 -04:00
if (entry == null)
continue;
2022-12-14 20:46:24 -08:00
uint address = entry.PointerToRawData;
uint size = entry.SizeOfData;
2023-09-13 00:08:11 -04:00
#if NET48
2022-12-14 20:46:24 -08:00
byte[] entryData = ReadFromDataSource((int)address, (int)size);
2023-09-13 00:08:11 -04:00
#else
byte[]? entryData = ReadFromDataSource((int)address, (int)size);
#endif
2023-01-05 22:42:54 -08:00
if (entryData == null)
continue;
2022-12-20 14:19:48 -08:00
2022-12-14 21:07:02 -08:00
// If we have CodeView debug data, try to parse it
2023-09-04 23:44:45 -04:00
if (entry.DebugType == SabreTools.Models.PortableExecutable.DebugType.IMAGE_DEBUG_TYPE_CODEVIEW)
2022-12-14 21:07:02 -08:00
{
// Read the signature
int offset = 0;
uint signature = entryData.ReadUInt32(ref offset);
// Reset the offset
offset = 0;
// NB10
if (signature == 0x3031424E)
{
var nb10ProgramDatabase = entryData.AsNB10ProgramDatabase(ref offset);
if (nb10ProgramDatabase != null)
{
_debugData[i] = nb10ProgramDatabase;
continue;
}
}
// RSDS
else if (signature == 0x53445352)
{
var rsdsProgramDatabase = entryData.AsRSDSProgramDatabase(ref offset);
if (rsdsProgramDatabase != null)
{
_debugData[i] = rsdsProgramDatabase;
continue;
}
}
}
else
{
_debugData[i] = entryData;
}
2022-12-14 20:46:24 -08:00
}
}
#endregion
2022-12-03 20:56:06 -08:00
#region Resource Data
/// <summary>
/// Find dialog box resources by title
/// </summary>
/// <param name="title">Dialog box title to check for</param>
/// <returns>Enumerable of matching resources</returns>
#if NET48
2023-09-04 23:44:45 -04:00
public IEnumerable<SabreTools.Models.PortableExecutable.DialogBoxResource> FindDialogByTitle(string title)
#else
public IEnumerable<SabreTools.Models.PortableExecutable.DialogBoxResource?> FindDialogByTitle(string title)
#endif
2022-12-03 20:56:06 -08:00
{
// Ensure that we have the resource data cached
if (ResourceData == null)
#if NET48
2023-09-04 23:44:45 -04:00
return Enumerable.Empty<SabreTools.Models.PortableExecutable.DialogBoxResource>();
#else
return Enumerable.Empty<SabreTools.Models.PortableExecutable.DialogBoxResource?>();
#endif
2022-12-03 20:56:06 -08:00
return ResourceData.Select(r => r.Value)
2023-09-04 23:44:45 -04:00
.Select(r => r as SabreTools.Models.PortableExecutable.DialogBoxResource)
2022-12-03 20:56:06 -08:00
.Where(d => d != null)
.Where(d =>
{
2023-09-13 00:08:11 -04:00
return (d?.DialogTemplate?.TitleResource?.Contains(title) ?? false)
|| (d?.ExtendedDialogTemplate?.TitleResource?.Contains(title) ?? false);
2022-12-03 20:56:06 -08:00
});
}
/// <summary>
/// Find dialog box resources by contained item title
/// </summary>
/// <param name="title">Dialog box item title to check for</param>
/// <returns>Enumerable of matching resources</returns>
#if NET48
2023-09-04 23:44:45 -04:00
public IEnumerable<SabreTools.Models.PortableExecutable.DialogBoxResource> FindDialogBoxByItemTitle(string title)
#else
public IEnumerable<SabreTools.Models.PortableExecutable.DialogBoxResource?> FindDialogBoxByItemTitle(string title)
#endif
2022-12-03 20:56:06 -08:00
{
// Ensure that we have the resource data cached
if (ResourceData == null)
#if NET48
2023-09-04 23:44:45 -04:00
return Enumerable.Empty<SabreTools.Models.PortableExecutable.DialogBoxResource>();
#else
return Enumerable.Empty<SabreTools.Models.PortableExecutable.DialogBoxResource?>();
#endif
2022-12-03 20:56:06 -08:00
return ResourceData.Select(r => r.Value)
2023-09-04 23:44:45 -04:00
.Select(r => r as SabreTools.Models.PortableExecutable.DialogBoxResource)
2022-12-03 20:56:06 -08:00
.Where(d => d != null)
.Where(d =>
{
2023-09-13 00:08:11 -04:00
if (d?.DialogItemTemplates != null)
2022-12-03 20:56:06 -08:00
{
return d.DialogItemTemplates
.Where(dit => dit?.TitleResource != null)
2023-09-13 00:08:11 -04:00
.Any(dit => dit?.TitleResource?.Contains(title) == true);
2022-12-03 20:56:06 -08:00
}
2023-09-13 00:08:11 -04:00
else if (d?.ExtendedDialogItemTemplates != null)
2022-12-03 20:56:06 -08:00
{
return d.ExtendedDialogItemTemplates
.Where(edit => edit?.TitleResource != null)
2023-09-13 00:08:11 -04:00
.Any(edit => edit?.TitleResource?.Contains(title) == true);
2022-12-03 20:56:06 -08:00
}
return false;
});
}
2022-12-04 21:11:55 -08:00
/// <summary>
/// Find string table resources by contained string entry
/// </summary>
/// <param name="entry">String entry to check for</param>
/// <returns>Enumerable of matching resources</returns>
#if NET48
2022-12-04 21:11:55 -08:00
public IEnumerable<Dictionary<int, string>> FindStringTableByEntry(string entry)
#else
public IEnumerable<Dictionary<int, string?>?> FindStringTableByEntry(string entry)
#endif
2022-12-04 21:11:55 -08:00
{
// Ensure that we have the resource data cached
if (ResourceData == null)
#if NET48
2022-12-04 21:11:55 -08:00
return Enumerable.Empty<Dictionary<int, string>>();
#else
return Enumerable.Empty<Dictionary<int, string?>?>();
#endif
2022-12-04 21:11:55 -08:00
return ResourceData.Select(r => r.Value)
#if NET48
2022-12-04 21:11:55 -08:00
.Select(r => r as Dictionary<int, string>)
#else
.Select(r => r as Dictionary<int, string?>)
#endif
2022-12-04 21:11:55 -08:00
.Where(st => st != null)
2023-09-12 17:12:23 -04:00
.Where(st => st?.Select(kvp => kvp.Value)?
.Any(s => s != null && s.Contains(entry)) == true);
2022-12-04 21:11:55 -08:00
}
2022-12-03 20:56:06 -08:00
/// <summary>
/// Find unparsed resources by type name
/// </summary>
/// <param name="typeName">Type name to check for</param>
/// <returns>Enumerable of matching resources</returns>
#if NET48
2022-12-03 20:56:06 -08:00
public IEnumerable<byte[]> FindResourceByNamedType(string typeName)
#else
public IEnumerable<byte[]?> FindResourceByNamedType(string typeName)
#endif
2022-12-03 20:56:06 -08:00
{
// Ensure that we have the resource data cached
if (ResourceData == null)
#if NET48
return Enumerable.Empty<byte[]>();
#else
return Enumerable.Empty<byte[]?>();
#endif
2022-12-03 20:56:06 -08:00
return ResourceData.Where(kvp => kvp.Key.Contains(typeName))
.Select(kvp => kvp.Value as byte[])
.Where(b => b != null);
}
/// <summary>
/// Find unparsed resources by string value
/// </summary>
/// <param name="value">String value to check for</param>
/// <returns>Enumerable of matching resources</returns>
#if NET48
2022-12-03 20:56:06 -08:00
public IEnumerable<byte[]> FindGenericResource(string value)
#else
public IEnumerable<byte[]?> FindGenericResource(string value)
#endif
2022-12-03 20:56:06 -08:00
{
// Ensure that we have the resource data cached
if (ResourceData == null)
#if NET48
return Enumerable.Empty<byte[]>();
#else
return Enumerable.Empty<byte[]?>();
#endif
2022-12-03 20:56:06 -08:00
return ResourceData.Select(r => r.Value)
.Select(r => r as byte[])
.Where(b => b != null)
.Where(b =>
{
try
{
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
string arrayAsASCII = Encoding.ASCII.GetString(b);
2023-09-12 17:12:23 -04:00
#else
string? arrayAsASCII = Encoding.ASCII.GetString(b!);
#endif
2022-12-03 20:56:06 -08:00
if (arrayAsASCII.Contains(value))
return true;
}
catch { }
try
{
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
string arrayAsUTF8 = Encoding.UTF8.GetString(b);
2023-09-12 17:12:23 -04:00
#else
string? arrayAsUTF8 = Encoding.UTF8.GetString(b!);
#endif
2022-12-03 20:56:06 -08:00
if (arrayAsUTF8.Contains(value))
return true;
}
catch { }
try
{
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
string arrayAsUnicode = Encoding.Unicode.GetString(b);
2023-09-12 17:12:23 -04:00
#else
string? arrayAsUnicode = Encoding.Unicode.GetString(b!);
#endif
2022-12-03 20:56:06 -08:00
if (arrayAsUnicode.Contains(value))
return true;
}
catch { }
return false;
2022-12-03 20:56:06 -08:00
});
}
#endregion
2022-12-03 14:22:54 -08:00
#region Resource Parsing
/// <summary>
/// Parse the resource directory table information
/// </summary>
2023-09-04 23:44:45 -04:00
private void ParseResourceDirectoryTable(SabreTools.Models.PortableExecutable.ResourceDirectoryTable table, List<object> types)
2022-12-03 14:22:54 -08:00
{
2023-09-13 00:08:11 -04:00
if (table?.Entries == null)
return;
for (int i = 0; i < table.Entries.Length; i++)
2022-12-03 14:22:54 -08:00
{
var entry = table.Entries[i];
2023-09-13 00:08:11 -04:00
if (entry == null)
continue;
2022-12-03 14:22:54 -08:00
var newTypes = new List<object>(types ?? new List<object>());
2023-09-12 17:12:23 -04:00
if (entry.Name?.UnicodeString != null)
newTypes.Add(Encoding.UTF8.GetString(entry.Name.UnicodeString));
2022-12-03 14:22:54 -08:00
else
newTypes.Add(entry.IntegerID);
ParseResourceDirectoryEntry(entry, newTypes);
}
}
/// <summary>
/// Parse the name resource directory entry information
/// </summary>
2023-09-04 23:44:45 -04:00
private void ParseResourceDirectoryEntry(SabreTools.Models.PortableExecutable.ResourceDirectoryEntry entry, List<object> types)
2022-12-03 14:22:54 -08:00
{
if (entry.DataEntry != null)
ParseResourceDataEntry(entry.DataEntry, types);
else if (entry.Subdirectory != null)
ParseResourceDirectoryTable(entry.Subdirectory, types);
}
/// <summary>
/// Parse the resource data entry information
/// </summary>
/// <remarks>
/// When caching the version information and assembly manifest, this code assumes that there is only one of each
/// of those resources in the entire exectuable. This means that only the last found version or manifest will
/// ever be cached.
/// </remarks>
2023-09-04 23:44:45 -04:00
private void ParseResourceDataEntry(SabreTools.Models.PortableExecutable.ResourceDataEntry entry, List<object> types)
2022-12-03 14:22:54 -08:00
{
// Create the key and value objects
string key = types == null ? $"UNKNOWN_{Guid.NewGuid()}" : string.Join(", ", types);
2023-09-13 00:08:11 -04:00
#if NET48
2022-12-03 14:22:54 -08:00
object value = entry.Data;
2023-09-13 00:08:11 -04:00
#else
object? value = entry.Data;
#endif
2022-12-03 14:22:54 -08:00
// If we have a known resource type
if (types != null && types.Count > 0 && types[0] is uint resourceType)
{
try
2022-12-03 14:22:54 -08:00
{
2023-09-04 23:44:45 -04:00
switch ((SabreTools.Models.PortableExecutable.ResourceType)resourceType)
{
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_CURSOR:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_BITMAP:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_ICON:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_MENU:
value = entry.AsMenu();
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_DIALOG:
value = entry.AsDialogBox();
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_STRING:
value = entry.AsStringTable();
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_FONTDIR:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_FONT:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_ACCELERATOR:
value = entry.AsAcceleratorTableResource();
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_RCDATA:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_MESSAGETABLE:
value = entry.AsMessageResourceData();
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_GROUP_CURSOR:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_GROUP_ICON:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_VERSION:
_versionInfo = entry.AsVersionInfo();
value = _versionInfo;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_DLGINCLUDE:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_PLUGPLAY:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_VXD:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_ANICURSOR:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_ANIICON:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_HTML:
value = entry.Data;
break;
2023-09-04 23:44:45 -04:00
case SabreTools.Models.PortableExecutable.ResourceType.RT_MANIFEST:
_assemblyManifest = entry.AsAssemblyManifest();
value = _versionInfo;
break;
default:
value = entry.Data;
break;
}
}
catch
{
// Fall back on byte array data for malformed items
value = entry.Data;
2022-12-03 14:22:54 -08:00
}
}
// If we have a custom resource type
else if (types != null && types.Count > 0 && types[0] is string)
{
value = entry.Data;
}
// Add the key and value to the cache
_resourceData[key] = value;
}
#endregion
2022-12-03 20:56:06 -08:00
#region Sections
/// <summary>
/// Determine if a section is contained within the section table
/// </summary>
/// <param name="sectionName">Name of the section to check for</param>
/// <param name="exact">True to enable exact matching of names, false for starts-with</param>
/// <returns>True if the section is in the executable, false otherwise</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
public bool ContainsSection(string sectionName, bool exact = false)
2023-09-12 17:12:23 -04:00
#else
public bool ContainsSection(string? sectionName, bool exact = false)
#endif
2022-12-03 20:56:06 -08:00
{
2023-09-12 17:12:23 -04:00
// If no section name is provided
if (sectionName == null)
return false;
2022-12-03 20:56:06 -08:00
// Get all section names first
if (SectionNames == null)
return false;
// If we're checking exactly, return only exact matches
if (exact)
return SectionNames.Any(n => n.Equals(sectionName));
// Otherwise, check if section name starts with the value
else
return SectionNames.Any(n => n.StartsWith(sectionName));
}
2022-12-20 13:03:25 -08:00
/// <summary>
/// Get the section index corresponding to the entry point, if possible
/// </summary>
/// <returns>Section index on success, null on error</returns>
public int FindEntryPointSectionIndex()
{
2023-09-12 17:12:23 -04:00
// If the section table is missing
if (SectionTable == null)
return -1;
2023-09-13 00:08:11 -04:00
#if NET6_0_OR_GREATER
// If the address is missing
if (OH_AddressOfEntryPoint == null)
return -1;
#endif
2022-12-20 13:03:25 -08:00
// If we don't have an entry point
2023-09-13 00:08:11 -04:00
#if NET48
2022-12-20 13:03:25 -08:00
if (OH_AddressOfEntryPoint.ConvertVirtualAddress(SectionTable) == 0)
return -1;
// Otherwise, find the section it exists within
return OH_AddressOfEntryPoint.ContainingSectionIndex(SectionTable);
2023-09-13 00:08:11 -04:00
#else
if (OH_AddressOfEntryPoint.Value.ConvertVirtualAddress(SectionTable) == 0)
return -1;
// Otherwise, find the section it exists within
2023-09-13 00:29:21 -04:00
return OH_AddressOfEntryPoint.Value.ContainingSectionIndex(SectionTable
.Where(sh => sh != null)
.Cast<SabreTools.Models.PortableExecutable.SectionHeader>()
.ToArray());
2023-09-13 00:08:11 -04:00
#endif
2022-12-20 13:03:25 -08:00
}
2022-12-03 20:56:06 -08:00
/// <summary>
/// Get the first section based on name, if possible
/// </summary>
/// <param name="name">Name of the section to check for</param>
/// <param name="exact">True to enable exact matching of names, false for starts-with</param>
/// <returns>Section data on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-04 23:44:45 -04:00
public SabreTools.Models.PortableExecutable.SectionHeader GetFirstSection(string name, bool exact = false)
2023-09-12 17:12:23 -04:00
#else
public SabreTools.Models.PortableExecutable.SectionHeader? GetFirstSection(string? name, bool exact = false)
#endif
2022-12-03 20:56:06 -08:00
{
// If we have no sections
2023-09-12 17:12:23 -04:00
if (SectionNames == null || !SectionNames.Any() || SectionTable == null || !SectionTable.Any())
2022-12-03 20:56:06 -08:00
return null;
// If the section doesn't exist
if (!ContainsSection(name, exact))
return null;
// Get the first index of the section
int index = Array.IndexOf(SectionNames, name);
if (index == -1)
return null;
// Return the section
return SectionTable[index];
}
/// <summary>
/// Get the last section based on name, if possible
/// </summary>
/// <param name="name">Name of the section to check for</param>
/// <param name="exact">True to enable exact matching of names, false for starts-with</param>
/// <returns>Section data on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-04 23:44:45 -04:00
public SabreTools.Models.PortableExecutable.SectionHeader GetLastSection(string name, bool exact = false)
2023-09-12 17:12:23 -04:00
#else
public SabreTools.Models.PortableExecutable.SectionHeader? GetLastSection(string? name, bool exact = false)
#endif
2022-12-03 20:56:06 -08:00
{
// If we have no sections
2023-09-12 17:12:23 -04:00
if (SectionNames == null || !SectionNames.Any() || SectionTable == null || !SectionTable.Any())
2022-12-03 20:56:06 -08:00
return null;
// If the section doesn't exist
if (!ContainsSection(name, exact))
return null;
// Get the last index of the section
int index = Array.LastIndexOf(SectionNames, name);
if (index == -1)
return null;
// Return the section
return SectionTable[index];
}
/// <summary>
/// Get the section based on index, if possible
/// </summary>
/// <param name="index">Index of the section to check for</param>
/// <returns>Section data on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2023-09-04 23:44:45 -04:00
public SabreTools.Models.PortableExecutable.SectionHeader GetSection(int index)
2023-09-12 17:12:23 -04:00
#else
public SabreTools.Models.PortableExecutable.SectionHeader? GetSection(int index)
#endif
2022-12-03 20:56:06 -08:00
{
// If we have no sections
2022-12-05 11:01:22 -08:00
if (SectionTable == null || !SectionTable.Any())
2022-12-03 20:56:06 -08:00
return null;
// If the section doesn't exist
if (index < 0 || index >= SectionTable.Length)
return null;
// Return the section
return SectionTable[index];
}
/// <summary>
/// Get the first section data based on name, if possible
/// </summary>
/// <param name="name">Name of the section to check for</param>
/// <param name="exact">True to enable exact matching of names, false for starts-with</param>
/// <returns>Section data on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
public byte[] GetFirstSectionData(string name, bool exact = false)
2023-09-12 17:12:23 -04:00
#else
public byte[]? GetFirstSectionData(string? name, bool exact = false)
#endif
2022-12-03 20:56:06 -08:00
{
// If we have no sections
2023-09-12 17:12:23 -04:00
if (SectionNames == null || !SectionNames.Any() || SectionTable == null || !SectionTable.Any())
2022-12-03 20:56:06 -08:00
return null;
// If the section doesn't exist
if (!ContainsSection(name, exact))
return null;
// Get the first index of the section
int index = Array.IndexOf(SectionNames, name);
2022-12-09 14:59:31 -08:00
return GetSectionData(index);
}
2022-12-03 20:56:06 -08:00
/// <summary>
/// Get the last section data based on name, if possible
/// </summary>
/// <param name="name">Name of the section to check for</param>
/// <param name="exact">True to enable exact matching of names, false for starts-with</param>
/// <returns>Section data on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
public byte[] GetLastSectionData(string name, bool exact = false)
2023-09-12 17:12:23 -04:00
#else
public byte[]? GetLastSectionData(string? name, bool exact = false)
#endif
2022-12-03 20:56:06 -08:00
{
// If we have no sections
2023-09-12 17:12:23 -04:00
if (SectionNames == null || !SectionNames.Any() || SectionTable == null || !SectionTable.Any())
2022-12-03 20:56:06 -08:00
return null;
// If the section doesn't exist
if (!ContainsSection(name, exact))
return null;
// Get the last index of the section
int index = Array.LastIndexOf(SectionNames, name);
2022-12-09 14:59:31 -08:00
return GetSectionData(index);
2022-12-03 20:56:06 -08:00
}
/// <summary>
/// Get the section data based on index, if possible
/// </summary>
/// <param name="index">Index of the section to check for</param>
/// <returns>Section data on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
public byte[] GetSectionData(int index)
2023-09-12 17:12:23 -04:00
#else
public byte[]? GetSectionData(int index)
#endif
2022-12-03 20:56:06 -08:00
{
// If we have no sections
2023-09-12 17:12:23 -04:00
if (SectionNames == null || !SectionNames.Any() || SectionTable == null || !SectionTable.Any())
2022-12-03 20:56:06 -08:00
return null;
// If the section doesn't exist
if (index < 0 || index >= SectionTable.Length)
return null;
// Get the section data from the table
2022-12-05 11:01:22 -08:00
var section = SectionTable[index];
2023-09-12 17:12:23 -04:00
if (section == null)
return null;
2022-12-05 11:01:22 -08:00
uint address = section.VirtualAddress.ConvertVirtualAddress(SectionTable);
2022-12-03 20:56:06 -08:00
if (address == 0)
return null;
// Set the section size
uint size = section.SizeOfRawData;
lock (_sourceDataLock)
2022-12-03 20:56:06 -08:00
{
2022-12-03 22:13:17 -08:00
// Create the section data array if we have to
if (_sectionData == null)
_sectionData = new byte[SectionNames.Length][];
2022-12-03 20:56:06 -08:00
// If we already have cached data, just use that immediately
if (_sectionData[index] != null)
2022-12-03 20:56:06 -08:00
return _sectionData[index];
// Populate the raw section data based on the source
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-03 20:56:06 -08:00
byte[] sectionData = ReadFromDataSource((int)address, (int)size);
2023-09-12 17:12:23 -04:00
#else
byte[]? sectionData = ReadFromDataSource((int)address, (int)size);
#endif
2022-12-03 20:56:06 -08:00
// Cache and return the section data, even if null
_sectionData[index] = sectionData;
return sectionData;
}
}
2022-12-09 11:53:58 -08:00
/// <summary>
/// Get the first section strings based on name, if possible
/// </summary>
/// <param name="name">Name of the section to check for</param>
/// <param name="exact">True to enable exact matching of names, false for starts-with</param>
/// <returns>Section strings on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-09 11:53:58 -08:00
public List<string> GetFirstSectionStrings(string name, bool exact = false)
2023-09-12 17:12:23 -04:00
#else
public List<string>? GetFirstSectionStrings(string? name, bool exact = false)
#endif
2022-12-09 11:53:58 -08:00
{
// If we have no sections
2023-09-12 17:12:23 -04:00
if (SectionNames == null || !SectionNames.Any() || SectionTable == null || !SectionTable.Any())
2022-12-09 11:53:58 -08:00
return null;
// If the section doesn't exist
if (!ContainsSection(name, exact))
return null;
// Get the first index of the section
int index = Array.IndexOf(SectionNames, name);
2022-12-09 14:59:31 -08:00
return GetSectionStrings(index);
2022-12-09 11:53:58 -08:00
}
/// <summary>
/// Get the last section strings based on name, if possible
/// </summary>
/// <param name="name">Name of the section to check for</param>
/// <param name="exact">True to enable exact matching of names, false for starts-with</param>
/// <returns>Section strings on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-09 11:53:58 -08:00
public List<string> GetLastSectionStrings(string name, bool exact = false)
2023-09-12 17:12:23 -04:00
#else
public List<string>? GetLastSectionStrings(string? name, bool exact = false)
#endif
2022-12-09 11:53:58 -08:00
{
// If we have no sections
2023-09-12 17:12:23 -04:00
if (SectionNames == null || !SectionNames.Any() || SectionTable == null || !SectionTable.Any())
2022-12-09 11:53:58 -08:00
return null;
// If the section doesn't exist
if (!ContainsSection(name, exact))
return null;
// Get the last index of the section
int index = Array.LastIndexOf(SectionNames, name);
2022-12-09 14:59:31 -08:00
return GetSectionStrings(index);
2022-12-09 11:53:58 -08:00
}
/// <summary>
/// Get the section strings based on index, if possible
/// </summary>
2022-12-09 14:59:31 -08:00
/// <param name="index">Index of the section to check for</param>
2022-12-09 11:53:58 -08:00
/// <returns>Section strings on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-09 11:53:58 -08:00
public List<string> GetSectionStrings(int index)
2023-09-12 17:12:23 -04:00
#else
public List<string>? GetSectionStrings(int index)
#endif
2022-12-09 11:53:58 -08:00
{
// If we have no sections
2023-09-12 17:12:23 -04:00
if (SectionNames == null || !SectionNames.Any() || SectionTable == null || !SectionTable.Any())
2022-12-09 11:53:58 -08:00
return null;
// If the section doesn't exist
if (index < 0 || index >= SectionTable.Length)
return null;
// Get the section data from the table
var section = SectionTable[index];
2023-09-13 00:08:11 -04:00
if (section == null)
return null;
2022-12-09 11:53:58 -08:00
uint address = section.VirtualAddress.ConvertVirtualAddress(SectionTable);
if (address == 0)
return null;
// Set the section size
uint size = section.SizeOfRawData;
lock (_sourceDataLock)
{
// Create the section string array if we have to
if (_sectionStringData == null)
_sectionStringData = new List<string>[SectionNames.Length];
// If we already have cached data, just use that immediately
if (_sectionStringData[index] != null)
return _sectionStringData[index];
// Populate the section string data based on the source
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-09 11:53:58 -08:00
List<string> sectionStringData = ReadStringsFromDataSource((int)address, (int)size);
2023-09-12 17:12:23 -04:00
#else
List<string>? sectionStringData = ReadStringsFromDataSource((int)address, (int)size);
#endif
2022-12-09 11:53:58 -08:00
// Cache and return the section string data, even if null
_sectionStringData[index] = sectionStringData;
return sectionStringData;
}
}
2022-12-03 20:56:06 -08:00
#endregion
2022-12-14 17:24:14 -08:00
#region Tables
/// <summary>
/// Get the table data based on index, if possible
/// </summary>
/// <param name="index">Index of the table to check for</param>
/// <returns>Table data on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-14 17:24:14 -08:00
public byte[] GetTableData(int index)
2023-09-12 17:12:23 -04:00
#else
public byte[]? GetTableData(int index)
#endif
2022-12-14 17:24:14 -08:00
{
// If the table doesn't exist
if (index < 0 || index > 16)
return null;
// Get the virtual address and size from the entries
uint virtualAddress = 0, size = 0;
switch (index)
{
case 1:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ExportTable?.VirtualAddress ?? 0;
size = OH_ExportTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 2:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ImportTable?.VirtualAddress ?? 0;
size = OH_ImportTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 3:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ResourceTable?.VirtualAddress ?? 0;
size = OH_ResourceTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 4:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ExceptionTable?.VirtualAddress ?? 0;
size = OH_ExceptionTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 5:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_CertificateTable?.VirtualAddress ?? 0;
size = OH_CertificateTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 6:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_BaseRelocationTable?.VirtualAddress ?? 0;
size = OH_BaseRelocationTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 7:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_Debug?.VirtualAddress ?? 0;
size = OH_Debug?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 8: // Architecture Table
virtualAddress = 0;
size = 0;
2022-12-20 14:19:48 -08:00
break;
2022-12-14 17:24:14 -08:00
case 9:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_GlobalPtr?.VirtualAddress ?? 0;
size = OH_GlobalPtr?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 10:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ThreadLocalStorageTable?.VirtualAddress ?? 0;
size = OH_ThreadLocalStorageTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 11:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_LoadConfigTable?.VirtualAddress ?? 0;
size = OH_LoadConfigTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 12:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_BoundImport?.VirtualAddress ?? 0;
size = OH_BoundImport?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 13:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ImportAddressTable?.VirtualAddress ?? 0;
size = OH_ImportAddressTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 14:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_DelayImportDescriptor?.VirtualAddress ?? 0;
size = OH_DelayImportDescriptor?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 15:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_CLRRuntimeHeader?.VirtualAddress ?? 0;
size = OH_CLRRuntimeHeader?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 16: // Reserved
virtualAddress = 0;
size = 0;
break;
}
2023-09-12 17:12:23 -04:00
// If there is no section table
if (SectionTable == null)
return null;
2022-12-14 17:24:14 -08:00
// Get the physical address from the virtual one
uint address = virtualAddress.ConvertVirtualAddress(SectionTable);
if (address == 0 || size == 0)
return null;
2022-12-20 14:19:48 -08:00
lock (_sourceDataLock)
2022-12-14 17:24:14 -08:00
{
// Create the table data array if we have to
if (_tableData == null)
_tableData = new byte[16][];
// If we already have cached data, just use that immediately
if (_tableData[index] != null)
return _tableData[index];
// Populate the raw table data based on the source
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-14 17:24:14 -08:00
byte[] tableData = ReadFromDataSource((int)address, (int)size);
2023-09-12 17:12:23 -04:00
#else
byte[]? tableData = ReadFromDataSource((int)address, (int)size);
#endif
2022-12-14 17:24:14 -08:00
// Cache and return the table data, even if null
_tableData[index] = tableData;
return tableData;
}
}
/// <summary>
/// Get the table strings based on index, if possible
/// </summary>
/// <param name="index">Index of the table to check for</param>
/// <returns>Table strings on success, null on error</returns>
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-14 17:24:14 -08:00
public List<string> GetTableStrings(int index)
2023-09-12 17:12:23 -04:00
#else
public List<string>? GetTableStrings(int index)
#endif
2022-12-14 17:24:14 -08:00
{
// If the table doesn't exist
if (index < 0 || index > 16)
return null;
// Get the virtual address and size from the entries
uint virtualAddress = 0, size = 0;
switch (index)
{
case 1:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ExportTable?.VirtualAddress ?? 0;
size = OH_ExportTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 2:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ImportTable?.VirtualAddress ?? 0;
size = OH_ImportTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 3:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ResourceTable?.VirtualAddress ?? 0;
size = OH_ResourceTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 4:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ExceptionTable?.VirtualAddress ?? 0;
size = OH_ExceptionTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 5:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_CertificateTable?.VirtualAddress ?? 0;
size = OH_CertificateTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 6:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_BaseRelocationTable?.VirtualAddress ?? 0;
size = OH_BaseRelocationTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 7:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_Debug?.VirtualAddress ?? 0;
size = OH_Debug?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 8: // Architecture Table
virtualAddress = 0;
size = 0;
break;
case 9:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_GlobalPtr?.VirtualAddress ?? 0;
size = OH_GlobalPtr?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 10:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ThreadLocalStorageTable?.VirtualAddress ?? 0;
size = OH_ThreadLocalStorageTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 11:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_LoadConfigTable?.VirtualAddress ?? 0;
size = OH_LoadConfigTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 12:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_BoundImport?.VirtualAddress ?? 0;
size = OH_BoundImport?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 13:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_ImportAddressTable?.VirtualAddress ?? 0;
size = OH_ImportAddressTable?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 14:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_DelayImportDescriptor?.VirtualAddress ?? 0;
size = OH_DelayImportDescriptor?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 15:
2023-09-13 00:08:11 -04:00
virtualAddress = OH_CLRRuntimeHeader?.VirtualAddress ?? 0;
size = OH_CLRRuntimeHeader?.Size ?? 0;
2022-12-14 17:24:14 -08:00
break;
case 16: // Reserved
virtualAddress = 0;
size = 0;
break;
}
2023-09-12 17:12:23 -04:00
// If there is no section table
if (SectionTable == null)
return null;
2022-12-14 17:24:14 -08:00
// Get the physical address from the virtual one
uint address = virtualAddress.ConvertVirtualAddress(SectionTable);
if (address == 0 || size == 0)
return null;
lock (_sourceDataLock)
{
// Create the table string array if we have to
if (_tableStringData == null)
_tableStringData = new List<string>[16];
// If we already have cached data, just use that immediately
if (_tableStringData[index] != null)
return _tableStringData[index];
// Populate the table string data based on the source
2023-09-12 17:12:23 -04:00
#if NET48
2022-12-14 17:24:14 -08:00
List<string> tableStringData = ReadStringsFromDataSource((int)address, (int)size);
2023-09-12 17:12:23 -04:00
#else
List<string>? tableStringData = ReadStringsFromDataSource((int)address, (int)size);
#endif
2022-12-14 17:24:14 -08:00
// Cache and return the table string data, even if null
_tableStringData[index] = tableStringData;
return tableStringData;
}
}
#endregion
2022-12-02 15:20:44 -08:00
}
}