2022-12-02 16:39:49 -08:00
using System ;
using System.Collections.Generic ;
using System.IO ;
2022-12-02 22:24:22 -08:00
using System.Linq ;
2022-12-02 16:39:49 -08:00
using System.Text ;
using System.Xml ;
2023-03-07 12:42:39 -05:00
using BinaryObjectScanner.ASN1 ;
2023-03-07 12:04:48 -05:00
using BinaryObjectScanner.Utilities ;
2023-03-07 16:59:14 -05:00
using static BinaryObjectScanner . Builders . 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
{
2022-12-02 20:05:20 -08:00
public class PortableExecutable : WrapperBase
2022-12-02 15:20:44 -08:00
{
2023-01-18 11:18:53 -08:00
#region Descriptive Properties
/// <inheritdoc/>
public override string Description = > "Portable Executable (PE)" ;
#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"/>
2022-12-28 14:50:48 -08:00
public string Stub_Magic = > _executable . Stub . Header . Magic ;
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.LastPageBytes"/>
public ushort Stub_LastPageBytes = > _executable . Stub . Header . LastPageBytes ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.Pages"/>
public ushort Stub_Pages = > _executable . Stub . Header . Pages ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.RelocationItems"/>
public ushort Stub_RelocationItems = > _executable . Stub . Header . RelocationItems ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.HeaderParagraphSize"/>
public ushort Stub_HeaderParagraphSize = > _executable . Stub . Header . HeaderParagraphSize ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.MinimumExtraParagraphs"/>
public ushort Stub_MinimumExtraParagraphs = > _executable . Stub . Header . MinimumExtraParagraphs ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.MaximumExtraParagraphs"/>
public ushort Stub_MaximumExtraParagraphs = > _executable . Stub . Header . MaximumExtraParagraphs ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.InitialSSValue"/>
public ushort Stub_InitialSSValue = > _executable . Stub . Header . InitialSSValue ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.InitialSPValue"/>
2022-12-05 11:01:22 -08:00
public ushort Stub_InitialSPValue = > _executable . Stub . Header . InitialSPValue ;
2022-12-02 15:35:10 -08:00
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.Checksum"/>
public ushort Stub_Checksum = > _executable . Stub . Header . Checksum ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.InitialIPValue"/>
public ushort Stub_InitialIPValue = > _executable . Stub . Header . InitialIPValue ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.InitialCSValue"/>
public ushort Stub_InitialCSValue = > _executable . Stub . Header . InitialCSValue ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.RelocationTableAddr"/>
public ushort Stub_RelocationTableAddr = > _executable . Stub . Header . RelocationTableAddr ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.OverlayNumber"/>
public ushort Stub_OverlayNumber = > _executable . Stub . Header . OverlayNumber ;
#endregion
#region PE Extensions
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.Reserved1"/>
public ushort [ ] Stub_Reserved1 = > _executable . Stub . Header . Reserved1 ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.OEMIdentifier"/>
public ushort Stub_OEMIdentifier = > _executable . Stub . Header . OEMIdentifier ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.OEMInformation"/>
public ushort Stub_OEMInformation = > _executable . Stub . Header . OEMInformation ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.Reserved2"/>
public ushort [ ] Stub_Reserved2 = > _executable . Stub . Header . Reserved2 ;
/// <inheritdoc cref="Models.MSDOS.ExecutableHeader.NewExeHeaderAddr"/>
public uint Stub_NewExeHeaderAddr = > _executable . Stub . Header . NewExeHeaderAddr ;
#endregion
#endregion
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.Executable.Signature"/>
2022-12-28 15:09:31 -08:00
public string Signature = > _executable . Signature ;
2022-12-02 16:16:12 -08:00
#region COFF File Header
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.Machine"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . MachineType Machine = > _executable . COFFFileHeader . Machine ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.NumberOfSections"/>
public ushort NumberOfSections = > _executable . COFFFileHeader . NumberOfSections ;
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.TimeDateStamp"/>
public uint TimeDateStamp = > _executable . COFFFileHeader . TimeDateStamp ;
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.PointerToSymbolTable"/>
public uint PointerToSymbolTable = > _executable . COFFFileHeader . PointerToSymbolTable ;
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.NumberOfSymbols"/>
public uint NumberOfSymbols = > _executable . COFFFileHeader . NumberOfSymbols ;
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.SizeOfOptionalHeader"/>
public uint SizeOfOptionalHeader = > _executable . COFFFileHeader . SizeOfOptionalHeader ;
/// <inheritdoc cref="Models.PortableExecutable.COFFFileHeader.Characteristics"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . Characteristics Characteristics = > _executable . COFFFileHeader . Characteristics ;
2022-12-02 16:16:12 -08:00
#endregion
#region Optional Header
#region Standard Fields
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Machine"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . OptionalHeaderMagicNumber OH_Magic = > _executable . OptionalHeader . Magic ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MajorLinkerVersion"/>
public byte OH_MajorLinkerVersion = > _executable . OptionalHeader . MajorLinkerVersion ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MinorLinkerVersion"/>
public byte OH_MinorLinkerVersion = > _executable . OptionalHeader . MinorLinkerVersion ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfCode"/>
public uint OH_SizeOfCode = > _executable . OptionalHeader . SizeOfCode ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfInitializedData"/>
public uint OH_SizeOfInitializedData = > _executable . OptionalHeader . SizeOfInitializedData ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfUninitializedData"/>
public uint OH_SizeOfUninitializedData = > _executable . OptionalHeader . SizeOfUninitializedData ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.AddressOfEntryPoint"/>
public uint OH_AddressOfEntryPoint = > _executable . OptionalHeader . AddressOfEntryPoint ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.BaseOfCode"/>
public uint OH_BaseOfCode = > _executable . OptionalHeader . BaseOfCode ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.BaseOfData"/>
2022-12-02 21:20:52 -08:00
public uint? OH_BaseOfData = > _executable . OptionalHeader . Magic = = Models . PortableExecutable . OptionalHeaderMagicNumber . PE32
2022-12-02 16:16:12 -08:00
? ( uint? ) _executable . OptionalHeader . BaseOfData
: null ;
#endregion
#region Windows - Specific Fields
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ImageBase_PE32"/>
2022-12-02 21:20:52 -08:00
public ulong OH_ImageBase = > _executable . OptionalHeader . Magic = = Models . PortableExecutable . OptionalHeaderMagicNumber . PE32
2022-12-02 16:16:12 -08:00
? _executable . OptionalHeader . ImageBase_PE32
: _executable . OptionalHeader . ImageBase_PE32Plus ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SectionAlignment"/>
public uint OH_SectionAlignment = > _executable . OptionalHeader . SectionAlignment ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.FileAlignment"/>
public uint OH_FileAlignment = > _executable . OptionalHeader . FileAlignment ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MajorOperatingSystemVersion"/>
public ushort OH_MajorOperatingSystemVersion = > _executable . OptionalHeader . MajorOperatingSystemVersion ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MinorOperatingSystemVersion"/>
public ushort OH_MinorOperatingSystemVersion = > _executable . OptionalHeader . MinorOperatingSystemVersion ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MajorImageVersion"/>
public ushort OH_MajorImageVersion = > _executable . OptionalHeader . MajorImageVersion ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MinorImageVersion"/>
public ushort OH_MinorImageVersion = > _executable . OptionalHeader . MinorImageVersion ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MajorSubsystemVersion"/>
public ushort OH_MajorSubsystemVersion = > _executable . OptionalHeader . MajorSubsystemVersion ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.MinorSubsystemVersion"/>
public ushort OH_MinorSubsystemVersion = > _executable . OptionalHeader . MinorSubsystemVersion ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Win32VersionValue"/>
public uint OH_Win32VersionValue = > _executable . OptionalHeader . Win32VersionValue ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfImage"/>
public uint OH_SizeOfImage = > _executable . OptionalHeader . SizeOfImage ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfHeaders"/>
public uint OH_SizeOfHeaders = > _executable . OptionalHeader . SizeOfHeaders ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.CheckSum"/>
public uint OH_CheckSum = > _executable . OptionalHeader . CheckSum ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Subsystem"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . WindowsSubsystem OH_Subsystem = > _executable . OptionalHeader . Subsystem ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.DllCharacteristics"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DllCharacteristics OH_DllCharacteristics = > _executable . OptionalHeader . DllCharacteristics ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfStackReserve_PE32"/>
2022-12-02 21:20:52 -08:00
public ulong OH_SizeOfStackReserve = > _executable . OptionalHeader . Magic = = Models . PortableExecutable . OptionalHeaderMagicNumber . PE32
2022-12-02 16:16:12 -08:00
? _executable . OptionalHeader . SizeOfStackReserve_PE32
: _executable . OptionalHeader . SizeOfStackReserve_PE32Plus ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfStackCommit_PE32"/>
2022-12-02 21:20:52 -08:00
public ulong OH_SizeOfStackCommit = > _executable . OptionalHeader . Magic = = Models . PortableExecutable . OptionalHeaderMagicNumber . PE32
2022-12-02 16:16:12 -08:00
? _executable . OptionalHeader . SizeOfStackCommit_PE32
: _executable . OptionalHeader . SizeOfStackCommit_PE32Plus ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfHeapReserve_PE32"/>
2022-12-02 21:20:52 -08:00
public ulong OH_SizeOfHeapReserve = > _executable . OptionalHeader . Magic = = Models . PortableExecutable . OptionalHeaderMagicNumber . PE32
2022-12-02 16:16:12 -08:00
? _executable . OptionalHeader . SizeOfHeapReserve_PE32
: _executable . OptionalHeader . SizeOfHeapReserve_PE32Plus ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.SizeOfHeapCommit_PE32"/>
2022-12-02 21:20:52 -08:00
public ulong OH_SizeOfHeapCommit = > _executable . OptionalHeader . Magic = = Models . PortableExecutable . OptionalHeaderMagicNumber . PE32
2022-12-02 16:16:12 -08:00
? _executable . OptionalHeader . SizeOfHeapCommit_PE32
: _executable . OptionalHeader . SizeOfHeapCommit_PE32Plus ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.LoaderFlags"/>
public uint OH_LoaderFlags = > _executable . OptionalHeader . LoaderFlags ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.NumberOfRvaAndSizes"/>
public uint OH_NumberOfRvaAndSizes = > _executable . OptionalHeader . NumberOfRvaAndSizes ;
#endregion
#region Data Directories
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ExportTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_ExportTable = > _executable . OptionalHeader . ExportTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ImportTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_ImportTable = > _executable . OptionalHeader . ImportTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ResourceTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_ResourceTable = > _executable . OptionalHeader . ResourceTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ExceptionTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_ExceptionTable = > _executable . OptionalHeader . ExceptionTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.CertificateTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_CertificateTable = > _executable . OptionalHeader . CertificateTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.BaseRelocationTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_BaseRelocationTable = > _executable . OptionalHeader . BaseRelocationTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Debug"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_Debug = > _executable . OptionalHeader . Debug ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Architecture"/>
public ulong OH_Architecture = > _executable . OptionalHeader . Architecture ;
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.GlobalPtr"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_GlobalPtr = > _executable . OptionalHeader . GlobalPtr ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ThreadLocalStorageTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_ThreadLocalStorageTable = > _executable . OptionalHeader . ThreadLocalStorageTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.LoadConfigTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_LoadConfigTable = > _executable . OptionalHeader . LoadConfigTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.BoundImport"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_BoundImport = > _executable . OptionalHeader . BoundImport ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.ImportAddressTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_ImportAddressTable = > _executable . OptionalHeader . ImportAddressTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.DelayImportDescriptor"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_DelayImportDescriptor = > _executable . OptionalHeader . DelayImportDescriptor ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.CLRRuntimeHeader"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DataDirectory OH_CLRRuntimeHeader = > _executable . OptionalHeader . CLRRuntimeHeader ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.OptionalHeader.Reserved"/>
public ulong OH_Reserved = > _executable . OptionalHeader . Reserved ;
#endregion
#endregion
#region Tables
/// <inheritdoc cref="Models.PortableExecutable.SectionTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . SectionHeader [ ] SectionTable = > _executable . SectionTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFSymbolTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . COFFSymbolTableEntry [ ] COFFSymbolTable = > _executable . COFFSymbolTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.COFFStringTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . COFFStringTable COFFStringTable = > _executable . COFFStringTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.AttributeCertificateTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . AttributeCertificateTableEntry [ ] AttributeCertificateTable = > _executable . AttributeCertificateTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.DelayLoadDirectoryTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DelayLoadDirectoryTable DelayLoadDirectoryTable = > _executable . DelayLoadDirectoryTable ;
2022-12-02 16:16:12 -08:00
#endregion
#region Sections
2022-12-04 23:17:34 -08:00
/// <inheritdoc cref="Models.PortableExecutable.BaseRelocationTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . BaseRelocationBlock [ ] BaseRelocationTable = > _executable . BaseRelocationTable ;
2022-12-04 23:17:34 -08:00
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.DebugTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . DebugTable DebugTable = > _executable . DebugTable ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.ExportTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . ExportTable ExportTable = > _executable . ExportTable ;
2022-12-02 16:16:12 -08:00
2022-12-02 22:24:22 -08:00
/// <inheritdoc cref="Models.PortableExecutable.ExportTable.ExportNameTable"/>
public string [ ] ExportNameTable = > _executable . ExportTable ? . ExportNameTable ? . Strings ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.ImportTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . ImportTable ImportTable = > _executable . ImportTable ;
2022-12-02 16:16:12 -08:00
2022-12-02 22:24:22 -08:00
/// <inheritdoc cref="Models.PortableExecutable.ImportTable.HintNameTable"/>
public string [ ] ImportHintNameTable = > _executable . ImportTable ? . HintNameTable ! = null
? _executable . ImportTable . HintNameTable . Select ( entry = > entry . Name ) . ToArray ( )
: null ;
2022-12-02 16:16:12 -08:00
/// <inheritdoc cref="Models.PortableExecutable.ResourceDirectoryTable"/>
2023-03-08 17:49:14 -05:00
public Models . PortableExecutable . ResourceDirectoryTable ResourceDirectoryTable = > _executable . ResourceDirectoryTable ;
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>
public byte [ ] HeaderPaddingData
{
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
// Populate the raw header padding data based on the source
uint headerStartAddress = Stub_NewExeHeaderAddr ;
uint firstSectionAddress = SectionTable . Select ( s = > s . PointerToRawData ) . Where ( s = > s ! = 0 ) . OrderBy ( s = > s ) . First ( ) ;
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>
public List < string > HeaderPaddingStrings
{
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
// Populate the raw header padding data based on the source
uint headerStartAddress = Stub_NewExeHeaderAddr ;
uint firstSectionAddress = SectionTable . Select ( s = > s . PointerToRawData ) . Where ( s = > s ! = 0 ) . OrderBy ( s = > s ) . First ( ) ;
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>
public byte [ ] EntryPointData
{
get
{
lock ( _sourceDataLock )
{
2022-12-27 22:25:16 -08:00
// If we have no entry point
int entryPointAddress = ( int ) OH_AddressOfEntryPoint . ConvertVirtualAddress ( SectionTable ) ;
if ( entryPointAddress = = 0 )
return null ;
// If the entry point matches with the start of a section, use that
int entryPointSection = FindEntryPointSectionIndex ( ) ;
if ( entryPointSection > = 0 & & OH_AddressOfEntryPoint = = SectionTable [ entryPointSection ] . VirtualAddress )
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 ;
}
}
}
2023-01-04 22:37:44 -08:00
/// <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 ;
// If we have certificate data, use that as the end
if ( OH_CertificateTable ! = null )
{
var certificateTable = _executable . OptionalHeader . CertificateTable ;
int certificateTableAddress = ( int ) certificateTable . VirtualAddress . ConvertVirtualAddress ( _executable . SectionTable ) ;
if ( certificateTableAddress ! = 0 & & certificateTableAddress < endOfFile )
endOfFile = certificateTableAddress ;
}
// Search through all sections and find the furthest a section goes
int endOfSectionData = - 1 ;
foreach ( var section in _executable . SectionTable )
{
// If we have an invalid section address
int sectionAddress = ( int ) section . VirtualAddress . ConvertVirtualAddress ( _executable . 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/"/>
2022-12-10 20:10:25 -08:00
public byte [ ] OverlayData
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 ;
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
{
var certificateTable = _executable . OptionalHeader . CertificateTable ;
int certificateTableAddress = ( int ) certificateTable . VirtualAddress . ConvertVirtualAddress ( _executable . 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 ;
foreach ( var section in _executable . SectionTable )
{
// If we have an invalid section address
int sectionAddress = ( int ) section . VirtualAddress . ConvertVirtualAddress ( _executable . 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 )
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>
public List < string > OverlayStrings
{
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 ;
2022-12-10 20:10:25 -08:00
// If we have certificate data, use that as the end
if ( OH_CertificateTable ! = null )
{
var certificateTable = _executable . OptionalHeader . CertificateTable ;
int certificateTableAddress = ( int ) certificateTable . VirtualAddress . ConvertVirtualAddress ( _executable . SectionTable ) ;
if ( certificateTableAddress ! = 0 & & certificateTableAddress < endOfFile )
endOfFile = certificateTableAddress ;
}
// Search through all sections and find the furthest a section goes
int endOfSectionData = - 1 ;
foreach ( var section in _executable . SectionTable )
{
// If we have an invalid section address
int sectionAddress = ( int ) section . VirtualAddress . ConvertVirtualAddress ( _executable . 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 )
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 ;
}
}
}
2022-12-02 20:05:20 -08:00
/// <summary>
2022-12-03 20:56:06 -08:00
/// Sanitized section names
2022-12-02 20:05:20 -08:00
/// </summary>
public string [ ] SectionNames
{
get
{
2022-12-30 09:09:42 -08:00
lock ( _sourceDataLock )
2022-12-20 14:19:48 -08:00
{
2022-12-30 09:09:42 -08:00
// Use the cached data if possible
if ( _sectionNames ! = null )
return _sectionNames ;
2022-12-02 20:05:20 -08:00
2022-12-30 09:09:42 -08:00
// Otherwise, build and return the cached array
_sectionNames = new string [ _executable . SectionTable . Length ] ;
for ( int i = 0 ; i < _sectionNames . Length ; i + + )
{
var section = _executable . SectionTable [ i ] ;
// TODO: Handle long section names with leading `/`
byte [ ] sectionNameBytes = section . Name ;
string sectionNameString = Encoding . UTF8 . GetString ( sectionNameBytes ) . TrimEnd ( '\0' ) ;
_sectionNames [ i ] = sectionNameString ;
}
2022-12-20 14:19:48 -08:00
2022-12-30 09:09:42 -08:00
return _sectionNames ;
}
2022-12-02 20:05:20 -08:00
}
}
2022-12-03 20:56:06 -08:00
/// <summary>
/// Stub executable data, if it exists
/// </summary>
public byte [ ] StubExecutableData
{
get
{
2022-12-03 21:37:32 -08:00
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 ;
2022-12-03 20:56:06 -08:00
// Populate the raw stub executable data based on the source
int endOfStubHeader = 0x40 ;
int lengthOfStubExecutableData = ( int ) _executable . Stub . Header . NewExeHeaderAddr - endOfStubHeader ;
_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>
2022-12-14 21:07:02 -08:00
public Dictionary < int , object > DebugData
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>
public Dictionary < string , object > ResourceData
{
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"
/// </summary>
public string BuildGuid = > GetVersionInfoString ( "BuildGuid" ) ;
/// <summary>
/// "Build signature"
/// </summary>
public string BuildSignature = > GetVersionInfoString ( "BuildSignature" ) ;
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.
/// </summary>
public string Comments = > GetVersionInfoString ( "Comments" ) ;
/// <summary>
/// Company that produced the file—for example, "Microsoft Corporation" or
/// "Standard Microsystems Corporation, Inc." This string is required.
/// </summary>
public string CompanyName = > GetVersionInfoString ( "CompanyName" ) ;
2022-12-08 14:59:15 -08:00
/// <summary>
/// "Debug version"
/// </summary>
public string DebugVersion = > GetVersionInfoString ( "DebugVersion" ) ;
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.
/// </summary>
public string FileDescription = > GetVersionInfoString ( "FileDescription" ) ;
/// <summary>
/// Version number of the file—for example, "3.10" or "5.00.RC2". This string
/// is required.
/// </summary>
public string FileVersion = > GetVersionInfoString ( "FileVersion" ) ;
/// <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.
/// </summary>
public string InternalName = > GetVersionInfoString ( key : "InternalName" ) ;
/// <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.
/// </summary>
public string LegalCopyright = > GetVersionInfoString ( key : "LegalCopyright" ) ;
/// <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.
/// </summary>
public string LegalTrademarks = > GetVersionInfoString ( key : "LegalTrademarks" ) ;
/// <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.
/// </summary>
public string OriginalFilename = > GetVersionInfoString ( key : "OriginalFilename" ) ;
/// <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.
/// </summary>
public string PrivateBuild = > GetVersionInfoString ( key : "PrivateBuild" ) ;
2022-12-08 14:40:30 -08:00
/// <summary>
/// "Product GUID"
/// </summary>
public string ProductGuid = > GetVersionInfoString ( "ProductGuid" ) ;
2022-12-02 22:24:22 -08:00
/// <summary>
/// Name of the product with which the file is distributed. This string is required.
/// </summary>
public string ProductName = > GetVersionInfoString ( key : "ProductName" ) ;
/// <summary>
/// Version of the product with which the file is distributed—for example, "3.10" or
/// "5.00.RC2". This string is required.
/// </summary>
public string ProductVersion = > GetVersionInfoString ( key : "ProductVersion" ) ;
/// <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.
/// </summary>
2022-12-08 14:59:15 -08:00
public string SpecialBuild = > GetVersionInfoString ( key : "SpecialBuild" ) ? ? GetVersionInfoString ( key : "Special Build" ) ;
2022-12-02 22:24:22 -08:00
2022-12-08 14:40:30 -08:00
/// <summary>
/// "Trade name"
/// </summary>
public string TradeName = > GetVersionInfoString ( key : "TradeName" ) ;
2023-03-09 23:19:27 -05: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>
public string GetInternalVersion ( )
{
string version = this . FileVersion ;
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>
public string AssemblyDescription
{
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>
public string AssemblyVersion
{
get
{
var manifest = GetAssemblyManifest ( ) ;
return manifest ?
. AssemblyIdentities ?
. FirstOrDefault ( ai = > ! string . IsNullOrWhiteSpace ( ai . Version ) ) ?
. Version ;
}
}
#endregion
2022-12-02 15:20:44 -08:00
#endregion
#region Instance Variables
/// <summary>
/// Internal representation of the executable
/// </summary>
2023-03-08 17:49:14 -05:00
private Models . PortableExecutable . Executable _executable ;
2022-12-02 15:20:44 -08:00
2022-12-05 15:56:37 -08:00
/// <summary>
/// Header padding data, if it exists
/// </summary>
private byte [ ] _headerPaddingData = null ;
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>
private List < string > _headerPaddingStrings = null ;
2022-12-20 14:19:48 -08:00
/// <summary>
/// Entry point data, if it exists and isn't aligned to a section
/// </summary>
private byte [ ] _entryPointData = null ;
2023-01-04 22:37:44 -08:00
/// <summary>
/// Address of the overlay, if it exists
/// </summary>
private int? _overlayAddress = null ;
2022-12-02 17:19:59 -08:00
/// <summary>
2022-12-02 21:20:52 -08:00
/// Overlay data, if it exists
2022-12-02 17:19:59 -08:00
/// </summary>
2022-12-02 21:20:52 -08:00
private byte [ ] _overlayData = null ;
2022-12-02 17:19:59 -08:00
2022-12-10 20:10:25 -08:00
/// <summary>
/// Overlay strings, if they exist
/// </summary>
private List < string > _overlayStrings = null ;
2022-12-02 17:19:59 -08:00
/// <summary>
2022-12-03 20:56:06 -08:00
/// Stub executable data, if it exists
/// </summary>
private byte [ ] _stubExecutableData = null ;
/// <summary>
/// Sanitized section names
2022-12-02 17:19:59 -08:00
/// </summary>
2022-12-02 21:20:52 -08:00
private string [ ] _sectionNames = null ;
2022-12-02 17:19:59 -08:00
/// <summary>
/// Cached raw section data
/// </summary>
2022-12-03 20:56:06 -08:00
private byte [ ] [ ] _sectionData = null ;
2022-12-05 11:01:22 -08:00
2022-12-09 11:53:58 -08:00
/// <summary>
/// Cached found string data in sections
/// </summary>
private List < string > [ ] _sectionStringData = null ;
2022-12-14 17:24:14 -08:00
/// <summary>
/// Cached raw table data
/// </summary>
private byte [ ] [ ] _tableData = null ;
/// <summary>
/// Cached found string data in tables
/// </summary>
private List < string > [ ] _tableStringData = null ;
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>
private readonly Dictionary < string , object > _resourceData = new Dictionary < string , object > ( ) ;
/// <summary>
/// Cached version info data
/// </summary>
2023-03-08 17:49:14 -05:00
private Models . PortableExecutable . VersionInfo _versionInfo = null ;
2022-12-02 22:24:22 -08:00
/// <summary>
/// Cached assembly manifest data
/// </summary>
2023-03-08 17:49:14 -05:00
private Models . PortableExecutable . AssemblyManifest _assemblyManifest = null ;
2022-12-02 22:24:22 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
2022-12-03 21:37:32 -08:00
/// Lock object for reading from the source
2022-12-02 21:20:52 -08:00
/// </summary>
2022-12-03 21:37:32 -08:00
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
2022-12-02 15:20:44 -08:00
/// <summary>
/// Private constructor
/// </summary>
private PortableExecutable ( ) { }
/// <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>
public static PortableExecutable Create ( byte [ ] data , int offset )
{
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>
public static PortableExecutable Create ( Stream data )
{
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 ;
2022-12-22 16:02:10 -08:00
var executable = Builders . PortableExecutable . ParseExecutable ( data ) ;
2022-12-02 15:20:44 -08:00
if ( executable = = null )
return null ;
2022-12-02 17:19:59 -08:00
var wrapper = new PortableExecutable
{
_executable = executable ,
_dataSource = DataSource . Stream ,
_streamData = data ,
} ;
2022-12-02 15:20:44 -08:00
return wrapper ;
}
2022-12-02 17:19:59 -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>
public string GetVersionInfoString ( string key )
{
// 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
2022-12-03 22:55:03 -08:00
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
. SelectMany ( st = > st . Children )
. FirstOrDefault ( sd = > key . Equals ( sd . Key , StringComparison . OrdinalIgnoreCase ) ) ;
// 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-03-08 17:49:14 -05:00
private Models . PortableExecutable . AssemblyManifest GetAssemblyManifest ( )
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
2022-12-03 22:55:03 -08:00
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 ( )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
StringBuilder builder = new StringBuilder ( ) ;
builder . AppendLine ( "Portable Executable Information:" ) ;
builder . AppendLine ( "-------------------------" ) ;
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
// Stub
2023-01-13 14:04:21 -08:00
PrintStubHeader ( builder ) ;
PrintStubExtendedHeader ( builder ) ;
2022-12-02 21:20:52 -08:00
// Header
2023-01-13 14:04:21 -08:00
PrintCOFFFileHeader ( builder ) ;
PrintOptionalHeader ( builder ) ;
2022-12-02 21:20:52 -08:00
// Tables
2023-01-13 14:04:21 -08:00
PrintSectionTable ( builder ) ;
PrintCOFFSymbolTable ( builder ) ;
PrintAttributeCertificateTable ( builder ) ;
PrintDelayLoadDirectoryTable ( builder ) ;
2022-12-04 22:32:41 -08:00
// Named Sections
2023-01-13 14:04:21 -08:00
PrintBaseRelocationTable ( builder ) ;
PrintDebugTable ( builder ) ;
PrintExportTable ( builder ) ;
PrintImportTable ( builder ) ;
PrintResourceDirectoryTable ( builder ) ;
return builder ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print stub header information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintStubHeader ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " MS-DOS Stub Header Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
builder . AppendLine ( $" Magic number: {Stub_Magic}" ) ;
builder . AppendLine ( $" Last page bytes: {Stub_LastPageBytes} (0x{Stub_LastPageBytes:X})" ) ;
builder . AppendLine ( $" Pages: {Stub_Pages} (0x{Stub_Pages:X})" ) ;
builder . AppendLine ( $" Relocation items: {Stub_RelocationItems} (0x{Stub_RelocationItems:X})" ) ;
builder . AppendLine ( $" Header paragraph size: {Stub_HeaderParagraphSize} (0x{Stub_HeaderParagraphSize:X})" ) ;
builder . AppendLine ( $" Minimum extra paragraphs: {Stub_MinimumExtraParagraphs} (0x{Stub_MinimumExtraParagraphs:X})" ) ;
builder . AppendLine ( $" Maximum extra paragraphs: {Stub_MaximumExtraParagraphs} (0x{Stub_MaximumExtraParagraphs:X})" ) ;
builder . AppendLine ( $" Initial SS value: {Stub_InitialSSValue} (0x{Stub_InitialSSValue:X})" ) ;
builder . AppendLine ( $" Initial SP value: {Stub_InitialSPValue} (0x{Stub_InitialSPValue:X})" ) ;
builder . AppendLine ( $" Checksum: {Stub_Checksum} (0x{Stub_Checksum:X})" ) ;
builder . AppendLine ( $" Initial IP value: {Stub_InitialIPValue} (0x{Stub_InitialIPValue:X})" ) ;
builder . AppendLine ( $" Initial CS value: {Stub_InitialCSValue} (0x{Stub_InitialCSValue:X})" ) ;
builder . AppendLine ( $" Relocation table address: {Stub_RelocationTableAddr} (0x{Stub_RelocationTableAddr:X})" ) ;
builder . AppendLine ( $" Overlay number: {Stub_OverlayNumber} (0x{Stub_OverlayNumber:X})" ) ;
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print stub extended header information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintStubExtendedHeader ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " MS-DOS Stub Extended Header Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
builder . AppendLine ( $" Reserved words: {string.Join(" , ", Stub_Reserved1)}" ) ;
builder . AppendLine ( $" OEM identifier: {Stub_OEMIdentifier} (0x{Stub_OEMIdentifier:X})" ) ;
builder . AppendLine ( $" OEM information: {Stub_OEMInformation} (0x{Stub_OEMInformation:X})" ) ;
builder . AppendLine ( $" Reserved words: {string.Join(" , ", Stub_Reserved2)}" ) ;
builder . AppendLine ( $" New EXE header address: {Stub_NewExeHeaderAddr} (0x{Stub_NewExeHeaderAddr:X})" ) ;
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print COFF file header information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintCOFFFileHeader ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " COFF File Header Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
builder . AppendLine ( $" Signature: {Signature}" ) ;
builder . AppendLine ( $" Machine: {Machine} (0x{Machine:X})" ) ;
builder . AppendLine ( $" Number of sections: {NumberOfSections} (0x{NumberOfSections:X})" ) ;
builder . AppendLine ( $" Time/Date stamp: {TimeDateStamp} (0x{TimeDateStamp:X})" ) ;
builder . AppendLine ( $" Pointer to symbol table: {PointerToSymbolTable} (0x{PointerToSymbolTable:X})" ) ;
builder . AppendLine ( $" Number of symbols: {NumberOfSymbols} (0x{NumberOfSymbols:X})" ) ;
builder . AppendLine ( $" Size of optional header: {SizeOfOptionalHeader} (0x{SizeOfOptionalHeader:X})" ) ;
builder . AppendLine ( $" Characteristics: {Characteristics} (0x{Characteristics:X})" ) ;
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print optional header information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintOptionalHeader ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Optional Header Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( SizeOfOptionalHeader = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No optional header present" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Magic: {OH_Magic} (0x{OH_Magic:X})" ) ;
builder . AppendLine ( $" Major linker version: {OH_MajorLinkerVersion} (0x{OH_MajorLinkerVersion:X})" ) ;
builder . AppendLine ( $" Minor linker version: {OH_MinorLinkerVersion} (0x{OH_MinorLinkerVersion:X})" ) ;
builder . AppendLine ( $" Size of code section: {OH_SizeOfCode} (0x{OH_SizeOfCode:X})" ) ;
builder . AppendLine ( $" Size of initialized data: {OH_SizeOfInitializedData} (0x{OH_SizeOfInitializedData:X})" ) ;
builder . AppendLine ( $" Size of uninitialized data: {OH_SizeOfUninitializedData} (0x{OH_SizeOfUninitializedData:X})" ) ;
builder . AppendLine ( $" Address of entry point: {OH_AddressOfEntryPoint} (0x{OH_AddressOfEntryPoint:X})" ) ;
builder . AppendLine ( $" Base of code: {OH_BaseOfCode} (0x{OH_BaseOfCode:X})" ) ;
2022-12-05 11:01:22 -08:00
if ( OH_Magic = = Models . PortableExecutable . OptionalHeaderMagicNumber . PE32 )
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Base of data: {OH_BaseOfData} (0x{OH_BaseOfData:X})" ) ;
builder . AppendLine ( $" Image base: {OH_ImageBase} (0x{OH_ImageBase:X})" ) ;
builder . AppendLine ( $" Section alignment: {OH_SectionAlignment} (0x{OH_SectionAlignment:X})" ) ;
builder . AppendLine ( $" File alignment: {OH_FileAlignment} (0x{OH_FileAlignment:X})" ) ;
builder . AppendLine ( $" Major operating system version: {OH_MajorOperatingSystemVersion} (0x{OH_MajorOperatingSystemVersion:X})" ) ;
builder . AppendLine ( $" Minor operating system version: {OH_MinorOperatingSystemVersion} (0x{OH_MinorOperatingSystemVersion:X})" ) ;
builder . AppendLine ( $" Major image version: {OH_MajorImageVersion} (0x{OH_MajorImageVersion:X})" ) ;
builder . AppendLine ( $" Minor image version: {OH_MinorImageVersion} (0x{OH_MinorImageVersion:X})" ) ;
builder . AppendLine ( $" Major subsystem version: {OH_MajorSubsystemVersion} (0x{OH_MajorSubsystemVersion:X})" ) ;
builder . AppendLine ( $" Minor subsystem version: {OH_MinorSubsystemVersion} (0x{OH_MinorSubsystemVersion:X})" ) ;
builder . AppendLine ( $" Win32 version value: {OH_Win32VersionValue} (0x{OH_Win32VersionValue:X})" ) ;
builder . AppendLine ( $" Size of image: {OH_SizeOfImage} (0x{OH_SizeOfImage:X})" ) ;
builder . AppendLine ( $" Size of headers: {OH_SizeOfHeaders} (0x{OH_SizeOfHeaders:X})" ) ;
builder . AppendLine ( $" Checksum: {OH_CheckSum} (0x{OH_CheckSum:X})" ) ;
builder . AppendLine ( $" Subsystem: {OH_Subsystem} (0x{OH_Subsystem:X})" ) ;
builder . AppendLine ( $" DLL characteristics: {OH_DllCharacteristics} (0x{OH_DllCharacteristics:X})" ) ;
builder . AppendLine ( $" Size of stack reserve: {OH_SizeOfStackReserve} (0x{OH_SizeOfStackReserve:X})" ) ;
builder . AppendLine ( $" Size of stack commit: {OH_SizeOfStackCommit} (0x{OH_SizeOfStackCommit:X})" ) ;
builder . AppendLine ( $" Size of heap reserve: {OH_SizeOfHeapReserve} (0x{OH_SizeOfHeapReserve:X})" ) ;
builder . AppendLine ( $" Size of heap commit: {OH_SizeOfHeapCommit} (0x{OH_SizeOfHeapCommit:X})" ) ;
builder . AppendLine ( $" Loader flags: {OH_LoaderFlags} (0x{OH_LoaderFlags:X})" ) ;
builder . AppendLine ( $" Number of data-directory entries: {OH_NumberOfRvaAndSizes} (0x{OH_NumberOfRvaAndSizes:X})" ) ;
2022-12-05 11:01:22 -08:00
if ( OH_ExportTable ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Export Table (1)" ) ;
builder . AppendLine ( $" Virtual address: {OH_ExportTable.VirtualAddress} (0x{OH_ExportTable.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_ExportTable.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_ExportTable.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_ExportTable.Size} (0x{OH_ExportTable.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_ImportTable ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Import Table (2)" ) ;
builder . AppendLine ( $" Virtual address: {OH_ImportTable.VirtualAddress} (0x{OH_ImportTable.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_ImportTable.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_ImportTable.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_ImportTable.Size} (0x{OH_ImportTable.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_ResourceTable ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Resource Table (3)" ) ;
builder . AppendLine ( $" Virtual address: {OH_ResourceTable.VirtualAddress} (0x{OH_ResourceTable.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_ResourceTable.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_ResourceTable.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_ResourceTable.Size} (0x{OH_ResourceTable.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_ExceptionTable ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Exception Table (4)" ) ;
builder . AppendLine ( $" Virtual address: {OH_ExceptionTable.VirtualAddress} (0x{OH_ExceptionTable.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_ExceptionTable.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_ExceptionTable.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_ExceptionTable.Size} (0x{OH_ExceptionTable.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_CertificateTable ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Certificate Table (5)" ) ;
builder . AppendLine ( $" Virtual address: {OH_CertificateTable.VirtualAddress} (0x{OH_CertificateTable.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_CertificateTable.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_CertificateTable.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_CertificateTable.Size} (0x{OH_CertificateTable.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_BaseRelocationTable ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Base Relocation Table (6)" ) ;
builder . AppendLine ( $" Virtual address: {OH_BaseRelocationTable.VirtualAddress} (0x{OH_BaseRelocationTable.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_BaseRelocationTable.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_BaseRelocationTable.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_BaseRelocationTable.Size} (0x{OH_BaseRelocationTable.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_Debug ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Debug Table (7)" ) ;
builder . AppendLine ( $" Virtual address: {OH_Debug.VirtualAddress} (0x{OH_Debug.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_Debug.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_Debug.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_Debug.Size} (0x{OH_Debug.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_NumberOfRvaAndSizes > = 8 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Architecture Table (8)" ) ;
builder . AppendLine ( $" Virtual address: 0 (0x00000000)" ) ;
builder . AppendLine ( $" Physical address: 0 (0x00000000)" ) ;
builder . AppendLine ( $" Size: 0 (0x00000000)" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_GlobalPtr ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Global Pointer Register (9)" ) ;
builder . AppendLine ( $" Virtual address: {OH_GlobalPtr.VirtualAddress} (0x{OH_GlobalPtr.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_GlobalPtr.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_GlobalPtr.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_GlobalPtr.Size} (0x{OH_GlobalPtr.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_ThreadLocalStorageTable ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Thread Local Storage (TLS) Table (10)" ) ;
builder . AppendLine ( $" Virtual address: {OH_ThreadLocalStorageTable.VirtualAddress} (0x{OH_ThreadLocalStorageTable.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_ThreadLocalStorageTable.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_ThreadLocalStorageTable.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_ThreadLocalStorageTable.Size} (0x{OH_ThreadLocalStorageTable.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_LoadConfigTable ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Load Config Table (11)" ) ;
builder . AppendLine ( $" Virtual address: {OH_LoadConfigTable.VirtualAddress} (0x{OH_LoadConfigTable.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_LoadConfigTable.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_LoadConfigTable.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_LoadConfigTable.Size} (0x{OH_LoadConfigTable.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_BoundImport ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Bound Import Table (12)" ) ;
builder . AppendLine ( $" Virtual address: {OH_BoundImport.VirtualAddress} (0x{OH_BoundImport.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_BoundImport.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_BoundImport.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_BoundImport.Size} (0x{OH_BoundImport.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_ImportAddressTable ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Import Address Table (13)" ) ;
builder . AppendLine ( $" Virtual address: {OH_ImportAddressTable.VirtualAddress} (0x{OH_ImportAddressTable.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_ImportAddressTable.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_ImportAddressTable.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_ImportAddressTable.Size} (0x{OH_ImportAddressTable.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_DelayImportDescriptor ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Delay Import Descriptior (14)" ) ;
builder . AppendLine ( $" Virtual address: {OH_DelayImportDescriptor.VirtualAddress} (0x{OH_DelayImportDescriptor.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_DelayImportDescriptor.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_DelayImportDescriptor.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_DelayImportDescriptor.Size} (0x{OH_DelayImportDescriptor.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_CLRRuntimeHeader ! = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " CLR Runtime Header (15)" ) ;
builder . AppendLine ( $" Virtual address: {OH_CLRRuntimeHeader.VirtualAddress} (0x{OH_CLRRuntimeHeader.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {OH_CLRRuntimeHeader.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{OH_CLRRuntimeHeader.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size: {OH_CLRRuntimeHeader.Size} (0x{OH_CLRRuntimeHeader.Size:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-05 11:01:22 -08:00
if ( OH_NumberOfRvaAndSizes > = 16 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Reserved (16)" ) ;
builder . AppendLine ( $" Virtual address: 0 (0x00000000)" ) ;
builder . AppendLine ( $" Physical address: 0 (0x00000000)" ) ;
builder . AppendLine ( $" Size: 0 (0x00000000)" ) ;
2022-12-02 16:39:49 -08:00
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print section table information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintSectionTable ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Section Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( NumberOfSections = = 0 | | SectionTable . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No section table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < SectionTable . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
var entry = SectionTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Section Table Entry {i}" ) ;
builder . AppendLine ( $" Name: {Encoding.UTF8.GetString(entry.Name).TrimEnd('\0')}" ) ;
builder . AppendLine ( $" Virtual size: {entry.VirtualSize} (0x{entry.VirtualSize:X})" ) ;
builder . AppendLine ( $" Virtual address: {entry.VirtualAddress} (0x{entry.VirtualAddress:X})" ) ;
builder . AppendLine ( $" Physical address: {entry.VirtualAddress.ConvertVirtualAddress(SectionTable)} (0x{entry.VirtualAddress.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Size of raw data: {entry.SizeOfRawData} (0x{entry.SizeOfRawData:X})" ) ;
builder . AppendLine ( $" Pointer to raw data: {entry.PointerToRawData} (0x{entry.PointerToRawData:X})" ) ;
builder . AppendLine ( $" Pointer to relocations: {entry.PointerToRelocations} (0x{entry.PointerToRelocations:X})" ) ;
builder . AppendLine ( $" Pointer to linenumbers: {entry.PointerToLinenumbers} (0x{entry.PointerToLinenumbers:X})" ) ;
builder . AppendLine ( $" Number of relocations: {entry.NumberOfRelocations} (0x{entry.NumberOfRelocations:X})" ) ;
builder . AppendLine ( $" Number of linenumbers: {entry.NumberOfLinenumbers} (0x{entry.NumberOfLinenumbers:X})" ) ;
builder . AppendLine ( $" Characteristics: {entry.Characteristics} (0x{entry.Characteristics:X})" ) ;
2022-12-02 16:39:49 -08:00
// TODO: Add COFFRelocations
// TODO: Add COFFLineNumbers
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print COFF symbol table information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintCOFFSymbolTable ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " COFF Symbol Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( PointerToSymbolTable = = 0
| | NumberOfSymbols = = 0
2022-12-19 21:39:24 -08:00
| | COFFSymbolTable = = null
2022-12-05 11:01:22 -08:00
| | COFFSymbolTable . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No COFF symbol table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
int auxSymbolsRemaining = 0 ;
int currentSymbolType = 0 ;
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < COFFSymbolTable . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
var entry = COFFSymbolTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" COFF Symbol Table Entry {i} (Subtype {currentSymbolType})" ) ;
2022-12-02 16:39:49 -08:00
if ( currentSymbolType = = 0 )
{
if ( entry . ShortName ! = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Short name: {Encoding.UTF8.GetString(entry.ShortName).TrimEnd('\0')}" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Zeroes: {entry.Zeroes} (0x{entry.Zeroes:X})" ) ;
builder . AppendLine ( $" Offset: {entry.Offset} (0x{entry.Offset:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Value: {entry.Value} (0x{entry.Value:X})" ) ;
builder . AppendLine ( $" Section number: {entry.SectionNumber} (0x{entry.SectionNumber:X})" ) ;
builder . AppendLine ( $" Symbol type: {entry.SymbolType} (0x{entry.SymbolType:X})" ) ;
builder . AppendLine ( $" Storage class: {entry.StorageClass} (0x{entry.StorageClass:X})" ) ;
builder . AppendLine ( $" Number of aux symbols: {entry.NumberOfAuxSymbols} (0x{entry.NumberOfAuxSymbols:X})" ) ;
2022-12-02 16:39:49 -08:00
auxSymbolsRemaining = entry . NumberOfAuxSymbols ;
if ( auxSymbolsRemaining = = 0 )
continue ;
if ( entry . StorageClass = = Models . PortableExecutable . StorageClass . IMAGE_SYM_CLASS_EXTERNAL
& & entry . SymbolType = = Models . PortableExecutable . SymbolType . IMAGE_SYM_TYPE_FUNC
& & entry . SectionNumber > 0 )
{
currentSymbolType = 1 ;
}
else if ( entry . StorageClass = = Models . PortableExecutable . StorageClass . IMAGE_SYM_CLASS_FUNCTION
& & entry . ShortName ! = null
& & ( ( entry . ShortName [ 0 ] = = 0x2E & & entry . ShortName [ 1 ] = = 0x62 & & entry . ShortName [ 2 ] = = 0x66 ) // .bf
| | ( entry . ShortName [ 0 ] = = 0x2E & & entry . ShortName [ 1 ] = = 0x65 & & entry . ShortName [ 2 ] = = 0x66 ) ) ) // .ef
{
currentSymbolType = 2 ;
}
else if ( entry . StorageClass = = Models . PortableExecutable . StorageClass . IMAGE_SYM_CLASS_EXTERNAL
& & entry . SectionNumber = = ( ushort ) Models . PortableExecutable . SectionNumber . IMAGE_SYM_UNDEFINED
& & entry . Value = = 0 )
{
currentSymbolType = 3 ;
}
else if ( entry . StorageClass = = Models . PortableExecutable . StorageClass . IMAGE_SYM_CLASS_FILE )
{
// TODO: Symbol name should be ".file"
currentSymbolType = 4 ;
}
else if ( entry . StorageClass = = Models . PortableExecutable . StorageClass . IMAGE_SYM_CLASS_STATIC )
{
// TODO: Should have the name of a section (like ".text")
currentSymbolType = 5 ;
}
else if ( entry . StorageClass = = Models . PortableExecutable . StorageClass . IMAGE_SYM_CLASS_CLR_TOKEN )
{
currentSymbolType = 6 ;
}
}
else if ( currentSymbolType = = 1 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Tag index: {entry.AuxFormat1TagIndex} (0x{entry.AuxFormat1TagIndex:X})" ) ;
builder . AppendLine ( $" Total size: {entry.AuxFormat1TotalSize} (0x{entry.AuxFormat1TotalSize:X})" ) ;
builder . AppendLine ( $" Pointer to linenumber: {entry.AuxFormat1PointerToLinenumber} (0x{entry.AuxFormat1PointerToLinenumber:X})" ) ;
builder . AppendLine ( $" Pointer to next function: {entry.AuxFormat1PointerToNextFunction} (0x{entry.AuxFormat1PointerToNextFunction:X})" ) ;
builder . AppendLine ( $" Unused: {entry.AuxFormat1Unused} (0x{entry.AuxFormat1Unused:X})" ) ;
2022-12-02 16:39:49 -08:00
auxSymbolsRemaining - - ;
}
else if ( currentSymbolType = = 2 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Unused: {entry.AuxFormat2Unused1} (0x{entry.AuxFormat2Unused1:X})" ) ;
builder . AppendLine ( $" Linenumber: {entry.AuxFormat2Linenumber} (0x{entry.AuxFormat2Linenumber:X})" ) ;
builder . AppendLine ( $" Unused: {entry.AuxFormat2Unused2} (0x{entry.AuxFormat2Unused2:X})" ) ;
builder . AppendLine ( $" Pointer to next function: {entry.AuxFormat2PointerToNextFunction} (0x{entry.AuxFormat2PointerToNextFunction:X})" ) ;
builder . AppendLine ( $" Unused: {entry.AuxFormat2Unused3} (0x{entry.AuxFormat2Unused3:X})" ) ;
2022-12-02 16:39:49 -08:00
auxSymbolsRemaining - - ;
}
else if ( currentSymbolType = = 3 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Tag index: {entry.AuxFormat3TagIndex} (0x{entry.AuxFormat3TagIndex:X})" ) ;
builder . AppendLine ( $" Characteristics: {entry.AuxFormat3Characteristics} (0x{entry.AuxFormat3Characteristics:X})" ) ;
builder . AppendLine ( $" Unused: {BitConverter.ToString(entry.AuxFormat3Unused).Replace(" - ", string.Empty)}" ) ;
2022-12-02 16:39:49 -08:00
auxSymbolsRemaining - - ;
}
else if ( currentSymbolType = = 4 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" File name: {Encoding.ASCII.GetString(entry.AuxFormat4FileName).TrimEnd('\0')}" ) ;
2022-12-02 16:39:49 -08:00
auxSymbolsRemaining - - ;
}
else if ( currentSymbolType = = 5 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Length: {entry.AuxFormat5Length} (0x{entry.AuxFormat5Length:X})" ) ;
builder . AppendLine ( $" Number of relocations: {entry.AuxFormat5NumberOfRelocations} (0x{entry.AuxFormat5NumberOfRelocations:X})" ) ;
builder . AppendLine ( $" Number of linenumbers: {entry.AuxFormat5NumberOfLinenumbers} (0x{entry.AuxFormat5NumberOfLinenumbers:X})" ) ;
builder . AppendLine ( $" Checksum: {entry.AuxFormat5CheckSum} (0x{entry.AuxFormat5CheckSum:X})" ) ;
builder . AppendLine ( $" Number: {entry.AuxFormat5Number} (0x{entry.AuxFormat5Number:X})" ) ;
builder . AppendLine ( $" Selection: {entry.AuxFormat5Selection} (0x{entry.AuxFormat5Selection:X})" ) ;
builder . AppendLine ( $" Unused: {BitConverter.ToString(entry.AuxFormat5Unused).Replace(" - ", string.Empty)}" ) ;
2022-12-02 16:39:49 -08:00
auxSymbolsRemaining - - ;
}
else if ( currentSymbolType = = 6 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Aux type: {entry.AuxFormat6AuxType} (0x{entry.AuxFormat6AuxType:X})" ) ;
builder . AppendLine ( $" Reserved: {entry.AuxFormat6Reserved1} (0x{entry.AuxFormat6Reserved1:X})" ) ;
builder . AppendLine ( $" Symbol table index: {entry.AuxFormat6SymbolTableIndex} (0x{entry.AuxFormat6SymbolTableIndex:X})" ) ;
builder . AppendLine ( $" Reserved: {BitConverter.ToString(entry.AuxFormat6Reserved2).Replace(" - ", string.Empty)}" ) ;
2022-12-02 16:39:49 -08:00
auxSymbolsRemaining - - ;
}
// If we hit the last aux symbol, go back to normal format
if ( auxSymbolsRemaining = = 0 )
currentSymbolType = 0 ;
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
builder . AppendLine ( " COFF String Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( COFFStringTable = = null
| | COFFStringTable . Strings = = null
| | COFFStringTable . Strings . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No COFF string table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Total size: {COFFStringTable.TotalSize} (0x{COFFStringTable.TotalSize:X})" ) ;
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < COFFStringTable . Strings . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
string entry = COFFStringTable . Strings [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" COFF String Table Entry {i})" ) ;
builder . AppendLine ( $" Value: {entry}" ) ;
2022-12-02 16:39:49 -08:00
}
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print attribute certificate table information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintAttributeCertificateTable ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Attribute Certificate Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( OH_CertificateTable = = null
| | OH_CertificateTable . VirtualAddress = = 0
| | AttributeCertificateTable . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No attribute certificate table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < AttributeCertificateTable . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
var entry = AttributeCertificateTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Attribute Certificate Table Entry {i}" ) ;
builder . AppendLine ( $" Length: {entry.Length} (0x{entry.Length:X})" ) ;
builder . AppendLine ( $" Revision: {entry.Revision} (0x{entry.Revision:X})" ) ;
builder . AppendLine ( $" Certificate type: {entry.CertificateType} (0x{entry.CertificateType:X})" ) ;
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
if ( entry . CertificateType = = Models . PortableExecutable . WindowsCertificateType . WIN_CERT_TYPE_PKCS_SIGNED_DATA )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Certificate Data [Formatted]" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-15 22:07:12 -08:00
var topLevelValues = AbstractSyntaxNotationOne . Parse ( entry . Certificate , pointer : 0 ) ;
2022-12-02 16:39:49 -08:00
if ( topLevelValues = = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " INVALID DATA FOUND" ) ;
builder . AppendLine ( $" {BitConverter.ToString(entry.Certificate).Replace(" - ", string.Empty)}" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-15 22:07:12 -08:00
foreach ( TypeLengthValue tlv in topLevelValues )
2022-12-02 16:39:49 -08:00
{
string tlvString = tlv . Format ( paddingLevel : 4 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( tlvString ) ;
2022-12-02 16:39:49 -08:00
}
}
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Certificate Data [Binary]" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-03 13:17:29 -08:00
try
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" {BitConverter.ToString(entry.Certificate).Replace(" - ", string.Empty)}" ) ;
2022-12-03 13:17:29 -08:00
}
catch
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" [DATA TOO LARGE TO FORMAT]" ) ;
2022-12-03 13:17:29 -08:00
}
2022-12-02 16:39:49 -08:00
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print delay-load directory table information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintDelayLoadDirectoryTable ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Delay-Load Directory Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( OH_DelayImportDescriptor = = null
| | OH_DelayImportDescriptor . VirtualAddress = = 0
| | DelayLoadDirectoryTable = = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No delay-load directory table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Attributes: {DelayLoadDirectoryTable.Attributes} (0x{DelayLoadDirectoryTable.Attributes:X})" ) ;
builder . AppendLine ( $" Name RVA: {DelayLoadDirectoryTable.Name} (0x{DelayLoadDirectoryTable.Name:X})" ) ;
builder . AppendLine ( $" Module handle: {DelayLoadDirectoryTable.ModuleHandle} (0x{DelayLoadDirectoryTable.ModuleHandle:X})" ) ;
builder . AppendLine ( $" Delay import address table RVA: {DelayLoadDirectoryTable.DelayImportAddressTable} (0x{DelayLoadDirectoryTable.DelayImportAddressTable:X})" ) ;
builder . AppendLine ( $" Delay import name table RVA: {DelayLoadDirectoryTable.DelayImportNameTable} (0x{DelayLoadDirectoryTable.DelayImportNameTable:X})" ) ;
builder . AppendLine ( $" Bound delay import table RVA: {DelayLoadDirectoryTable.BoundDelayImportTable} (0x{DelayLoadDirectoryTable.BoundDelayImportTable:X})" ) ;
builder . AppendLine ( $" Unload delay import table RVA: {DelayLoadDirectoryTable.UnloadDelayImportTable} (0x{DelayLoadDirectoryTable.UnloadDelayImportTable:X})" ) ;
builder . AppendLine ( $" Timestamp: {DelayLoadDirectoryTable.TimeStamp} (0x{DelayLoadDirectoryTable.TimeStamp:X})" ) ;
2022-12-02 16:39:49 -08:00
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-04 22:32:41 -08:00
/// <summary>
/// Print base relocation table information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintBaseRelocationTable ( StringBuilder builder )
2022-12-04 22:32:41 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Base Relocation Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( OH_BaseRelocationTable = = null
| | OH_BaseRelocationTable . VirtualAddress = = 0
| | BaseRelocationTable = = null )
2022-12-04 22:32:41 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No base relocation table items" ) ;
2022-12-04 22:32:41 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < BaseRelocationTable . Length ; i + + )
2022-12-04 22:32:41 -08:00
{
2022-12-05 11:01:22 -08:00
var baseRelocationTableEntry = BaseRelocationTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Base Relocation Table Entry {i}" ) ;
builder . AppendLine ( $" Page RVA: {baseRelocationTableEntry.PageRVA} (0x{baseRelocationTableEntry.PageRVA:X})" ) ;
builder . AppendLine ( $" Page physical address: {baseRelocationTableEntry.PageRVA.ConvertVirtualAddress(SectionTable)} (0x{baseRelocationTableEntry.PageRVA.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Block size: {baseRelocationTableEntry.BlockSize} (0x{baseRelocationTableEntry.BlockSize:X})" ) ;
2022-12-04 22:32:41 -08:00
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Base Relocation Table {i} Type and Offset Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-04 22:32:41 -08:00
if ( baseRelocationTableEntry . TypeOffsetFieldEntries = = null | | baseRelocationTableEntry . TypeOffsetFieldEntries . Length = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No base relocation table type and offset entries" ) ;
2022-12-04 22:32:41 -08:00
}
else
{
for ( int j = 0 ; j < baseRelocationTableEntry . TypeOffsetFieldEntries . Length ; j + + )
{
var typeOffsetFieldEntry = baseRelocationTableEntry . TypeOffsetFieldEntries [ j ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Type and Offset Entry {j}" ) ;
builder . AppendLine ( $" Type: {typeOffsetFieldEntry.BaseRelocationType} (0x{typeOffsetFieldEntry.BaseRelocationType:X})" ) ;
builder . AppendLine ( $" Offset: {typeOffsetFieldEntry.Offset} (0x{typeOffsetFieldEntry.Offset:X})" ) ;
2022-12-04 22:32:41 -08:00
}
}
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-04 22:32:41 -08:00
}
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print debug table information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintDebugTable ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Debug Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( OH_Debug = = null
| | OH_Debug . VirtualAddress = = 0
| | DebugTable = = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No debug table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
// TODO: If more sections added, model this after the Export Table
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < DebugTable . DebugDirectoryTable . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
var debugDirectoryEntry = DebugTable . DebugDirectoryTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Debug Directory Table Entry {i}" ) ;
builder . AppendLine ( $" Characteristics: {debugDirectoryEntry.Characteristics} (0x{debugDirectoryEntry.Characteristics:X})" ) ;
builder . AppendLine ( $" Time/Date stamp: {debugDirectoryEntry.TimeDateStamp} (0x{debugDirectoryEntry.TimeDateStamp:X})" ) ;
builder . AppendLine ( $" Major version: {debugDirectoryEntry.MajorVersion} (0x{debugDirectoryEntry.MajorVersion:X})" ) ;
builder . AppendLine ( $" Minor version: {debugDirectoryEntry.MinorVersion} (0x{debugDirectoryEntry.MinorVersion:X})" ) ;
builder . AppendLine ( $" Debug type: {debugDirectoryEntry.DebugType} (0x{debugDirectoryEntry.DebugType:X})" ) ;
builder . AppendLine ( $" Size of data: {debugDirectoryEntry.SizeOfData} (0x{debugDirectoryEntry.SizeOfData:X})" ) ;
builder . AppendLine ( $" Address of raw data: {debugDirectoryEntry.AddressOfRawData} (0x{debugDirectoryEntry.AddressOfRawData:X})" ) ;
builder . AppendLine ( $" Pointer to raw data: {debugDirectoryEntry.PointerToRawData} (0x{debugDirectoryEntry.PointerToRawData:X})" ) ;
}
}
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print export table information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintExportTable ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Export Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( OH_ExportTable = = null
| | OH_ExportTable . VirtualAddress = = 0
| | ExportTable = = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No export table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
builder . AppendLine ( " Export Directory Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
builder . AppendLine ( $" Export flags: {ExportTable.ExportDirectoryTable.ExportFlags} (0x{ExportTable.ExportDirectoryTable.ExportFlags:X})" ) ;
builder . AppendLine ( $" Time/Date stamp: {ExportTable.ExportDirectoryTable.TimeDateStamp} (0x{ExportTable.ExportDirectoryTable.TimeDateStamp:X})" ) ;
builder . AppendLine ( $" Major version: {ExportTable.ExportDirectoryTable.MajorVersion} (0x{ExportTable.ExportDirectoryTable.MajorVersion:X})" ) ;
builder . AppendLine ( $" Minor version: {ExportTable.ExportDirectoryTable.MinorVersion} (0x{ExportTable.ExportDirectoryTable.MinorVersion:X})" ) ;
builder . AppendLine ( $" Name RVA: {ExportTable.ExportDirectoryTable.NameRVA} (0x{ExportTable.ExportDirectoryTable.NameRVA:X})" ) ;
builder . AppendLine ( $" Name: {ExportTable.ExportDirectoryTable.Name}" ) ;
builder . AppendLine ( $" Ordinal base: {ExportTable.ExportDirectoryTable.OrdinalBase} (0x{ExportTable.ExportDirectoryTable.OrdinalBase:X})" ) ;
builder . AppendLine ( $" Address table entries: {ExportTable.ExportDirectoryTable.AddressTableEntries} (0x{ExportTable.ExportDirectoryTable.AddressTableEntries:X})" ) ;
builder . AppendLine ( $" Number of name pointers: {ExportTable.ExportDirectoryTable.NumberOfNamePointers} (0x{ExportTable.ExportDirectoryTable.NumberOfNamePointers:X})" ) ;
builder . AppendLine ( $" Export address table RVA: {ExportTable.ExportDirectoryTable.ExportAddressTableRVA} (0x{ExportTable.ExportDirectoryTable.ExportAddressTableRVA:X})" ) ;
builder . AppendLine ( $" Name pointer table RVA: {ExportTable.ExportDirectoryTable.NamePointerRVA} (0x{ExportTable.ExportDirectoryTable.NamePointerRVA:X})" ) ;
builder . AppendLine ( $" Ordinal table RVA: {ExportTable.ExportDirectoryTable.OrdinalTableRVA} (0x{ExportTable.ExportDirectoryTable.OrdinalTableRVA:X})" ) ;
builder . AppendLine ( ) ;
builder . AppendLine ( " Export Address Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( ExportTable . ExportAddressTable = = null | | ExportTable . ExportAddressTable . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No export address table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < ExportTable . ExportAddressTable . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
var exportAddressTableEntry = ExportTable . ExportAddressTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Export Address Table Entry {i}" ) ;
builder . AppendLine ( $" Export RVA / Forwarder RVA: {exportAddressTableEntry.ExportRVA} (0x{exportAddressTableEntry.ExportRVA:X})" ) ;
2022-12-02 16:39:49 -08:00
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Name Pointer Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( ExportTable . NamePointerTable ? . Pointers = = null | | ExportTable . NamePointerTable . Pointers . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No name pointer table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < ExportTable . NamePointerTable . Pointers . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
var namePointerTableEntry = ExportTable . NamePointerTable . Pointers [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Name Pointer Table Entry {i}" ) ;
builder . AppendLine ( $" Pointer: {namePointerTableEntry} (0x{namePointerTableEntry:X})" ) ;
2022-12-02 16:39:49 -08:00
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Ordinal Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( ExportTable . OrdinalTable ? . Indexes = = null | | ExportTable . OrdinalTable . Indexes . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No ordinal table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < ExportTable . OrdinalTable . Indexes . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
var ordinalTableEntry = ExportTable . OrdinalTable . Indexes [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Ordinal Table Entry {i}" ) ;
builder . AppendLine ( $" Index: {ordinalTableEntry} (0x{ordinalTableEntry:X})" ) ;
2022-12-02 16:39:49 -08:00
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Export Name Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( ExportTable . ExportNameTable ? . Strings = = null | | ExportTable . ExportNameTable . Strings . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No export name table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < ExportTable . ExportNameTable . Strings . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
var exportNameTableEntry = ExportTable . ExportNameTable . Strings [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Export Name Table Entry {i}" ) ;
builder . AppendLine ( $" String: {exportNameTableEntry}" ) ;
2022-12-02 16:39:49 -08:00
}
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print import table information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintImportTable ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Import Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( OH_ImportTable = = null
| | OH_ImportTable . VirtualAddress = = 0
| | ImportTable = = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No import table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
builder . AppendLine ( " Import Directory Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( ImportTable . ImportDirectoryTable = = null | | ImportTable . ImportDirectoryTable . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No import directory table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < ImportTable . ImportDirectoryTable . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
var importDirectoryTableEntry = ImportTable . ImportDirectoryTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Import Directory Table Entry {i}" ) ;
builder . AppendLine ( $" Import lookup table RVA: {importDirectoryTableEntry.ImportLookupTableRVA} (0x{importDirectoryTableEntry.ImportLookupTableRVA:X})" ) ;
builder . AppendLine ( $" Import lookup table Physical Address: {importDirectoryTableEntry.ImportLookupTableRVA.ConvertVirtualAddress(SectionTable)} (0x{importDirectoryTableEntry.ImportLookupTableRVA.ConvertVirtualAddress(SectionTable):X})" ) ;
builder . AppendLine ( $" Time/Date stamp: {importDirectoryTableEntry.TimeDateStamp} (0x{importDirectoryTableEntry.TimeDateStamp:X})" ) ;
builder . AppendLine ( $" Forwarder chain: {importDirectoryTableEntry.ForwarderChain} (0x{importDirectoryTableEntry.ForwarderChain:X})" ) ;
builder . AppendLine ( $" Name RVA: {importDirectoryTableEntry.NameRVA} (0x{importDirectoryTableEntry.NameRVA:X})" ) ;
builder . AppendLine ( $" Name: {importDirectoryTableEntry.Name}" ) ;
builder . AppendLine ( $" Import address table RVA: {importDirectoryTableEntry.ImportAddressTableRVA} (0x{importDirectoryTableEntry.ImportAddressTableRVA:X})" ) ;
builder . AppendLine ( $" Import address table Physical Address: {importDirectoryTableEntry.ImportAddressTableRVA.ConvertVirtualAddress(SectionTable)} (0x{importDirectoryTableEntry.ImportAddressTableRVA.ConvertVirtualAddress(SectionTable):X})" ) ;
2022-12-02 16:39:49 -08:00
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Import Lookup Tables Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( ImportTable . ImportLookupTables = = null | | ImportTable . ImportLookupTables . Count = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No import lookup tables" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
foreach ( var kvp in ImportTable . ImportLookupTables )
2022-12-02 16:39:49 -08:00
{
int index = kvp . Key ;
var importLookupTable = kvp . Value ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
builder . AppendLine ( $" Import Lookup Table {index} Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-02 16:39:49 -08:00
if ( importLookupTable = = null | | importLookupTable . Length = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No import lookup table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
for ( int i = 0 ; i < importLookupTable . Length ; i + + )
{
var importLookupTableEntry = importLookupTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Import Lookup Table {index} Entry {i}" ) ;
builder . AppendLine ( $" Ordinal/Name flag: {importLookupTableEntry.OrdinalNameFlag} (0x{importLookupTableEntry.OrdinalNameFlag:X})" ) ;
2022-12-02 16:39:49 -08:00
if ( importLookupTableEntry . OrdinalNameFlag )
2022-12-05 13:57:07 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Ordinal number: {importLookupTableEntry.OrdinalNumber} (0x{importLookupTableEntry.OrdinalNumber:X})" ) ;
2022-12-05 13:57:07 -08:00
}
2022-12-02 16:39:49 -08:00
else
2022-12-05 13:57:07 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Hint/Name table RVA: {importLookupTableEntry.HintNameTableRVA} (0x{importLookupTableEntry.HintNameTableRVA:X})" ) ;
builder . AppendLine ( $" Hint/Name table Physical Address: {importLookupTableEntry.HintNameTableRVA.ConvertVirtualAddress(SectionTable)} (0x{importLookupTableEntry.HintNameTableRVA.ConvertVirtualAddress(SectionTable):X})" ) ;
2022-12-05 13:57:07 -08:00
}
2022-12-02 16:39:49 -08:00
}
}
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Import Address Tables Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( ImportTable . ImportAddressTables = = null | | ImportTable . ImportAddressTables . Count = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No import address tables" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
foreach ( var kvp in ImportTable . ImportAddressTables )
2022-12-02 16:39:49 -08:00
{
int index = kvp . Key ;
var importAddressTable = kvp . Value ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
builder . AppendLine ( $" Import Address Table {index} Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-02 16:39:49 -08:00
if ( importAddressTable = = null | | importAddressTable . Length = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No import address table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
for ( int i = 0 ; i < importAddressTable . Length ; i + + )
{
2022-12-05 13:52:15 -08:00
var importAddressTableEntry = importAddressTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Import Address Table {index} Entry {i}" ) ;
builder . AppendLine ( $" Ordinal/Name flag: {importAddressTableEntry.OrdinalNameFlag} (0x{importAddressTableEntry.OrdinalNameFlag:X})" ) ;
2022-12-05 13:52:15 -08:00
if ( importAddressTableEntry . OrdinalNameFlag )
2022-12-05 13:57:07 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Ordinal number: {importAddressTableEntry.OrdinalNumber} (0x{importAddressTableEntry.OrdinalNumber:X})" ) ;
2022-12-05 13:57:07 -08:00
}
2022-12-02 16:39:49 -08:00
else
2022-12-05 13:57:07 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Hint/Name table RVA: {importAddressTableEntry.HintNameTableRVA} (0x{importAddressTableEntry.HintNameTableRVA:X})" ) ;
builder . AppendLine ( $" Hint/Name table Physical Address: {importAddressTableEntry.HintNameTableRVA.ConvertVirtualAddress(SectionTable)} (0x{importAddressTableEntry.HintNameTableRVA.ConvertVirtualAddress(SectionTable):X})" ) ;
2022-12-05 13:57:07 -08:00
}
2022-12-02 16:39:49 -08:00
}
}
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Hint/Name Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( ImportTable . HintNameTable = = null | | ImportTable . HintNameTable . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No hint/name table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-05 11:01:22 -08:00
for ( int i = 0 ; i < ImportTable . HintNameTable . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-05 11:01:22 -08:00
var hintNameTableEntry = ImportTable . HintNameTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $" Hint/Name Table Entry {i}" ) ;
builder . AppendLine ( $" Hint: {hintNameTableEntry.Hint} (0x{hintNameTableEntry.Hint:X})" ) ;
builder . AppendLine ( $" Name: {hintNameTableEntry.Name}" ) ;
2022-12-02 16:39:49 -08:00
}
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 21:20:52 -08:00
}
2022-12-02 16:39:49 -08:00
2022-12-02 21:20:52 -08:00
/// <summary>
/// Print resource directory table information
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private void PrintResourceDirectoryTable ( StringBuilder builder )
2022-12-02 21:20:52 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " Resource Directory Table Information:" ) ;
builder . AppendLine ( " -------------------------" ) ;
2022-12-05 11:01:22 -08:00
if ( OH_ResourceTable = = null
| | OH_ResourceTable . VirtualAddress = = 0
| | ResourceDirectoryTable = = null )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( " No resource directory table items" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
PrintResourceDirectoryTable ( ResourceDirectoryTable , level : 0 , types : new List < object > ( ) , builder ) ;
2022-12-02 16:39:49 -08:00
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
}
/// <summary>
2022-12-02 22:24:22 -08:00
/// Pretty print the resource directory table information
2022-12-02 16:39:49 -08:00
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceDirectoryTable ( Models . PortableExecutable . ResourceDirectoryTable table , int level , List < object > types , StringBuilder builder )
2022-12-02 16:39:49 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Table level: {level}" ) ;
builder . AppendLine ( $"{padding}Characteristics: {table.Characteristics} (0x{table.Characteristics:X})" ) ;
builder . AppendLine ( $"{padding}Time/Date stamp: {table.TimeDateStamp} (0x{table.TimeDateStamp:X})" ) ;
builder . AppendLine ( $"{padding}Major version: {table.MajorVersion} (0x{table.MajorVersion:X})" ) ;
builder . AppendLine ( $"{padding}Minor version: {table.MinorVersion} (0x{table.MinorVersion:X})" ) ;
builder . AppendLine ( $"{padding}Number of name entries: {table.NumberOfNameEntries} (0x{table.NumberOfNameEntries:X})" ) ;
builder . AppendLine ( $"{padding}Number of ID entries: {table.NumberOfIDEntries} (0x{table.NumberOfIDEntries:X})" ) ;
builder . AppendLine ( ) ;
builder . AppendLine ( $"{padding}Entries" ) ;
builder . AppendLine ( $"{padding}-------------------------" ) ;
2022-12-03 14:22:54 -08:00
if ( table . NumberOfNameEntries = = 0 & & table . NumberOfIDEntries = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}No entries" ) ;
builder . AppendLine ( ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-03 14:22:54 -08:00
for ( int i = 0 ; i < table . Entries . Length ; i + + )
2022-12-02 16:39:49 -08:00
{
2022-12-03 14:22:54 -08:00
var entry = table . Entries [ i ] ;
2022-12-02 16:39:49 -08:00
var newTypes = new List < object > ( types ? ? new List < object > ( ) ) ;
2022-12-03 14:22:54 -08:00
if ( entry . Name ! = null )
newTypes . Add ( Encoding . UTF8 . GetString ( entry . Name . UnicodeString ? ? new byte [ 0 ] ) ) ;
else
newTypes . Add ( entry . IntegerID ) ;
2022-12-02 16:39:49 -08:00
2023-01-13 14:04:21 -08:00
PrintResourceDirectoryEntry ( entry , level + 1 , newTypes , builder ) ;
2022-12-02 16:39:49 -08:00
}
}
}
/// <summary>
2022-12-03 14:22:54 -08:00
/// Pretty print the resource directory entry information
2022-12-02 16:39:49 -08:00
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceDirectoryEntry ( Models . PortableExecutable . ResourceDirectoryEntry entry , int level , List < object > types , StringBuilder builder )
2022-12-02 16:39:49 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Item level: {level}" ) ;
2022-12-03 14:22:54 -08:00
if ( entry . NameOffset ! = default )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Name offset: {entry.NameOffset} (0x{entry.NameOffset:X})" ) ;
builder . AppendLine ( $"{padding}Name ({entry.Name.Length}): {Encoding.UTF8.GetString(entry.Name.UnicodeString ?? new byte[0])}" ) ;
2022-12-03 14:22:54 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Integer ID: {entry.IntegerID} (0x{entry.IntegerID:X})" ) ;
2022-12-03 14:22:54 -08:00
}
2022-12-02 16:39:49 -08:00
if ( entry . DataEntry ! = null )
2023-01-13 14:04:21 -08:00
PrintResourceDataEntry ( entry . DataEntry , level : level + 1 , types , builder ) ;
2022-12-02 16:39:49 -08:00
else if ( entry . Subdirectory ! = null )
2023-01-13 14:04:21 -08:00
PrintResourceDirectoryTable ( entry . Subdirectory , level : level + 1 , types , builder ) ;
2022-12-02 16:39:49 -08:00
}
/// <summary>
2022-12-02 22:24:22 -08:00
/// Pretty print the resource data entry information
2022-12-02 16:39:49 -08:00
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceDataEntry ( Models . PortableExecutable . ResourceDataEntry entry , int level , List < object > types , StringBuilder builder )
2022-12-02 16:39:49 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
// TODO: Use ordered list of base types to determine the shape of the data
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Base types: {string.Join(" , ", types)}" ) ;
2022-12-02 16:39:49 -08:00
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Entry level: {level}" ) ;
builder . AppendLine ( $"{padding}Data RVA: {entry.DataRVA} (0x{entry.DataRVA:X})" ) ;
builder . AppendLine ( $"{padding}Size: {entry.Size} (0x{entry.Size:X})" ) ;
builder . AppendLine ( $"{padding}Codepage: {entry.Codepage} (0x{entry.Codepage:X})" ) ;
builder . AppendLine ( $"{padding}Reserved: {entry.Reserved} (0x{entry.Reserved:X})" ) ;
2022-12-02 16:39:49 -08:00
// TODO: Print out per-type data
if ( types ! = null & & types . Count > 0 & & types [ 0 ] is uint resourceType )
{
switch ( ( Models . PortableExecutable . ResourceType ) resourceType )
{
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_CURSOR :
2023-01-13 14:04:21 -08:00
PrintResourceRT_CURSOR ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_BITMAP :
2023-01-13 14:04:21 -08:00
PrintResourceRT_BITMAP ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_ICON :
2023-01-13 14:04:21 -08:00
PrintResourceRT_ICON ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_MENU :
2023-01-13 14:04:21 -08:00
PrintResourceRT_MENU ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_DIALOG :
2023-01-13 14:04:21 -08:00
PrintResourceRT_DIALOG ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_STRING :
2023-01-13 14:04:21 -08:00
PrintResourceRT_STRING ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_FONTDIR :
2023-01-13 14:04:21 -08:00
PrintResourceRT_FONTDIR ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_FONT :
2023-01-13 14:04:21 -08:00
PrintResourceRT_FONT ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_ACCELERATOR :
2023-01-13 14:04:21 -08:00
PrintResourceRT_ACCELERATOR ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_RCDATA :
2023-01-13 14:04:21 -08:00
PrintResourceRT_RCDATA ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_MESSAGETABLE :
2023-01-13 14:04:21 -08:00
PrintResourceRT_MESSAGETABLE ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_GROUP_CURSOR :
2023-01-13 14:04:21 -08:00
PrintResourceRT_GROUP_CURSOR ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_GROUP_ICON :
2023-01-13 14:04:21 -08:00
PrintResourceRT_GROUP_ICON ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_VERSION :
2023-01-13 14:04:21 -08:00
PrintResourceRT_VERSION ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_DLGINCLUDE :
2023-01-13 14:04:21 -08:00
PrintResourceRT_DLGINCLUDE ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_PLUGPLAY :
2023-01-13 14:04:21 -08:00
PrintResourceRT_PLUGPLAY ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_VXD :
2023-01-13 14:04:21 -08:00
PrintResourceRT_VXD ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_ANICURSOR :
2023-01-13 14:04:21 -08:00
PrintResourceRT_ANICURSOR ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_ANIICON :
2023-01-13 14:04:21 -08:00
PrintResourceRT_ANIICON ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_HTML :
2023-01-13 14:04:21 -08:00
PrintResourceRT_HTML ( entry , level , builder ) ;
2022-12-02 16:39:49 -08:00
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_MANIFEST :
2023-01-13 14:04:21 -08:00
PrintResourceRT_MANIFEST ( entry , level , builder ) ;
2022-12-08 14:00:29 -08:00
break ;
default :
2023-01-13 14:04:21 -08:00
PrintResourceUNKNOWN ( entry , level , types [ 0 ] , builder ) ;
2022-12-08 14:00:29 -08:00
break ;
}
}
else if ( types ! = null & & types . Count > 0 & & types [ 0 ] is string resourceString )
{
2023-01-13 14:04:21 -08:00
PrintResourceUNKNOWN ( entry , level , types [ 0 ] , builder ) ;
2022-12-08 14:00:29 -08:00
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_CURSOR resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_CURSOR ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Hardware-dependent cursor resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_BITMAP resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_BITMAP ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Bitmap resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_ICON resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_ICON ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Hardware-dependent icon resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_MENU resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_MENU ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
Models . PortableExecutable . MenuResource menu = null ;
try { menu = entry . AsMenu ( ) ; } catch { }
if ( menu = = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Menu resource found, but malformed" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
if ( menu . MenuHeader ! = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Version: {menu.MenuHeader.Version} (0x{menu.MenuHeader.Version:X})" ) ;
builder . AppendLine ( $"{padding}Header size: {menu.MenuHeader.HeaderSize} (0x{menu.MenuHeader.HeaderSize:X})" ) ;
builder . AppendLine ( ) ;
builder . AppendLine ( $"{padding}Menu items" ) ;
builder . AppendLine ( $"{padding}-------------------------" ) ;
2022-12-08 14:00:29 -08:00
if ( menu . MenuItems = = null | | menu . MenuItems . Length = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}No menu items" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
for ( int i = 0 ; i < menu . MenuItems . Length ; i + + )
{
var menuItem = menu . MenuItems [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Menu item {i}" ) ;
2022-12-08 14:00:29 -08:00
if ( menuItem . NormalMenuText ! = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding} Resource info: {menuItem.NormalResInfo} (0x{menuItem.NormalResInfo:X})" ) ;
builder . AppendLine ( $"{padding} Menu text: {menuItem.NormalMenuText} (0x{menuItem.NormalMenuText:X})" ) ;
2022-12-08 14:00:29 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding} Item type: {menuItem.PopupItemType} (0x{menuItem.PopupItemType:X})" ) ;
builder . AppendLine ( $"{padding} State: {menuItem.PopupState} (0x{menuItem.PopupState:X})" ) ;
builder . AppendLine ( $"{padding} ID: {menuItem.PopupID} (0x{menuItem.PopupID:X})" ) ;
builder . AppendLine ( $"{padding} Resource info: {menuItem.PopupResInfo} (0x{menuItem.PopupResInfo:X})" ) ;
builder . AppendLine ( $"{padding} Menu text: {menuItem.PopupMenuText} (0x{menuItem.PopupMenuText:X})" ) ;
2022-12-08 14:00:29 -08:00
}
}
}
else if ( menu . ExtendedMenuHeader ! = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Version: {menu.ExtendedMenuHeader.Version} (0x{menu.ExtendedMenuHeader.Version:X})" ) ;
builder . AppendLine ( $"{padding}Offset: {menu.ExtendedMenuHeader.Offset} (0x{menu.ExtendedMenuHeader.Offset:X})" ) ;
builder . AppendLine ( $"{padding}Help ID: {menu.ExtendedMenuHeader.HelpID} (0x{menu.ExtendedMenuHeader.HelpID:X})" ) ;
builder . AppendLine ( ) ;
builder . AppendLine ( $"{padding}Menu items" ) ;
builder . AppendLine ( $"{padding}-------------------------" ) ;
2022-12-08 14:00:29 -08:00
if ( menu . ExtendedMenuHeader . Offset = = 0
| | menu . ExtendedMenuItems = = null
| | menu . ExtendedMenuItems . Length = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}No menu items" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
for ( int i = 0 ; i < menu . ExtendedMenuItems . Length ; i + + )
{
var menuItem = menu . ExtendedMenuItems [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Dialog item template {i}" ) ;
builder . AppendLine ( $"{padding} Item type: {menuItem.ItemType} (0x{menuItem.ItemType:X})" ) ;
builder . AppendLine ( $"{padding} State: {menuItem.State} (0x{menuItem.State:X})" ) ;
builder . AppendLine ( $"{padding} ID: {menuItem.ID} (0x{menuItem.ID:X})" ) ;
builder . AppendLine ( $"{padding} Flags: {menuItem.Flags} (0x{menuItem.Flags:X})" ) ;
builder . AppendLine ( $"{padding} Menu text: {menuItem.MenuText} (0x{menuItem.MenuText:X})" ) ;
2022-12-08 14:00:29 -08:00
}
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Menu resource found, but malformed" ) ;
2022-12-08 14:00:29 -08:00
}
}
/// <summary>
/// Print an RT_DIALOG resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_DIALOG ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
Models . PortableExecutable . DialogBoxResource dialogBox = null ;
try { dialogBox = entry . AsDialogBox ( ) ; } catch { }
if ( dialogBox = = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Dialog box resource found, but malformed" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
if ( dialogBox . DialogTemplate ! = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Style: {dialogBox.DialogTemplate.Style} (0x{dialogBox.DialogTemplate.Style:X})" ) ;
builder . AppendLine ( $"{padding}Extended style: {dialogBox.DialogTemplate.ExtendedStyle} (0x{dialogBox.DialogTemplate.ExtendedStyle:X})" ) ;
builder . AppendLine ( $"{padding}Item count: {dialogBox.DialogTemplate.ItemCount} (0x{dialogBox.DialogTemplate.ItemCount:X})" ) ;
builder . AppendLine ( $"{padding}X-coordinate of upper-left corner: {dialogBox.DialogTemplate.PositionX} (0x{dialogBox.DialogTemplate.PositionX:X})" ) ;
builder . AppendLine ( $"{padding}Y-coordinate of upper-left corner: {dialogBox.DialogTemplate.PositionY} (0x{dialogBox.DialogTemplate.PositionY:X})" ) ;
builder . AppendLine ( $"{padding}Width of the dialog box: {dialogBox.DialogTemplate.WidthX} (0x{dialogBox.DialogTemplate.WidthX:X})" ) ;
builder . AppendLine ( $"{padding}Height of the dialog box: {dialogBox.DialogTemplate.HeightY} (0x{dialogBox.DialogTemplate.HeightY:X})" ) ;
builder . AppendLine ( $"{padding}Menu resource: {dialogBox.DialogTemplate.MenuResource ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( $"{padding}Menu resource ordinal: {dialogBox.DialogTemplate.MenuResourceOrdinal} (0x{dialogBox.DialogTemplate.MenuResourceOrdinal:X})" ) ;
builder . AppendLine ( $"{padding}Class resource: {dialogBox.DialogTemplate.ClassResource ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( $"{padding}Class resource ordinal: {dialogBox.DialogTemplate.ClassResourceOrdinal} (0x{dialogBox.DialogTemplate.ClassResourceOrdinal:X})" ) ;
builder . AppendLine ( $"{padding}Title resource: {dialogBox.DialogTemplate.TitleResource ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( $"{padding}Point size value: {dialogBox.DialogTemplate.PointSizeValue} (0x{dialogBox.DialogTemplate.PointSizeValue:X})" ) ;
builder . AppendLine ( $"{padding}Typeface: {dialogBox.DialogTemplate.Typeface ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( ) ;
builder . AppendLine ( $"{padding}Dialog item templates" ) ;
builder . AppendLine ( $"{padding}-------------------------" ) ;
2022-12-08 14:00:29 -08:00
if ( dialogBox . DialogTemplate . ItemCount = = 0
| | dialogBox . DialogItemTemplates = = null
| | dialogBox . DialogItemTemplates . Length = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}No dialog item templates" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
for ( int i = 0 ; i < dialogBox . DialogItemTemplates . Length ; i + + )
{
var dialogItemTemplate = dialogBox . DialogItemTemplates [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Dialog item template {i}" ) ;
builder . AppendLine ( $"{padding} Style: {dialogItemTemplate.Style} (0x{dialogItemTemplate.Style:X})" ) ;
builder . AppendLine ( $"{padding} Extended style: {dialogItemTemplate.ExtendedStyle} (0x{dialogItemTemplate.ExtendedStyle:X})" ) ;
builder . AppendLine ( $"{padding} X-coordinate of upper-left corner: {dialogItemTemplate.PositionX} (0x{dialogItemTemplate.PositionX:X})" ) ;
builder . AppendLine ( $"{padding} Y-coordinate of upper-left corner: {dialogItemTemplate.PositionY} (0x{dialogItemTemplate.PositionY:X})" ) ;
builder . AppendLine ( $"{padding} Width of the control: {dialogItemTemplate.WidthX} (0x{dialogItemTemplate.WidthX:X})" ) ;
builder . AppendLine ( $"{padding} Height of the control: {dialogItemTemplate.HeightY} (0x{dialogItemTemplate.HeightY:X})" ) ;
builder . AppendLine ( $"{padding} ID: {dialogItemTemplate.ID} (0x{dialogItemTemplate.ID:X})" ) ;
builder . AppendLine ( $"{padding} Class resource: {dialogItemTemplate.ClassResource ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( $"{padding} Class resource ordinal: {dialogItemTemplate.ClassResourceOrdinal} (0x{dialogItemTemplate.ClassResourceOrdinal:X})" ) ;
builder . AppendLine ( $"{padding} Title resource: {dialogItemTemplate.TitleResource ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( $"{padding} Title resource ordinal: {dialogItemTemplate.TitleResourceOrdinal} (0x{dialogItemTemplate.TitleResourceOrdinal:X})" ) ;
builder . AppendLine ( $"{padding} Creation data size: {dialogItemTemplate.CreationDataSize} (0x{dialogItemTemplate.CreationDataSize:X})" ) ;
2022-12-08 14:00:29 -08:00
if ( dialogItemTemplate . CreationData ! = null & & dialogItemTemplate . CreationData . Length ! = 0 )
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding} Creation data: {BitConverter.ToString(dialogItemTemplate.CreationData).Replace(" - ", string.Empty)}" ) ;
2022-12-08 14:00:29 -08:00
else
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding} Creation data: [EMPTY]" ) ;
2022-12-08 14:00:29 -08:00
}
}
else if ( dialogBox . ExtendedDialogTemplate ! = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Version: {dialogBox.ExtendedDialogTemplate.Version} (0x{dialogBox.ExtendedDialogTemplate.Version:X})" ) ;
builder . AppendLine ( $"{padding}Signature: {dialogBox.ExtendedDialogTemplate.Signature} (0x{dialogBox.ExtendedDialogTemplate.Signature:X})" ) ;
builder . AppendLine ( $"{padding}Help ID: {dialogBox.ExtendedDialogTemplate.HelpID} (0x{dialogBox.ExtendedDialogTemplate.HelpID:X})" ) ;
builder . AppendLine ( $"{padding}Extended style: {dialogBox.ExtendedDialogTemplate.ExtendedStyle} (0x{dialogBox.ExtendedDialogTemplate.ExtendedStyle:X})" ) ;
builder . AppendLine ( $"{padding}Style: {dialogBox.ExtendedDialogTemplate.Style} (0x{dialogBox.ExtendedDialogTemplate.Style:X})" ) ;
builder . AppendLine ( $"{padding}Item count: {dialogBox.ExtendedDialogTemplate.DialogItems} (0x{dialogBox.ExtendedDialogTemplate.DialogItems:X})" ) ;
builder . AppendLine ( $"{padding}X-coordinate of upper-left corner: {dialogBox.ExtendedDialogTemplate.PositionX} (0x{dialogBox.ExtendedDialogTemplate.PositionX:X})" ) ;
builder . AppendLine ( $"{padding}Y-coordinate of upper-left corner: {dialogBox.ExtendedDialogTemplate.PositionY} (0x{dialogBox.ExtendedDialogTemplate.PositionY:X})" ) ;
builder . AppendLine ( $"{padding}Width of the dialog box: {dialogBox.ExtendedDialogTemplate.WidthX} (0x{dialogBox.ExtendedDialogTemplate.WidthX:X})" ) ;
builder . AppendLine ( $"{padding}Height of the dialog box: {dialogBox.ExtendedDialogTemplate.HeightY} (0x{dialogBox.ExtendedDialogTemplate.HeightY:X})" ) ;
builder . AppendLine ( $"{padding}Menu resource: {dialogBox.ExtendedDialogTemplate.MenuResource ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( $"{padding}Menu resource ordinal: {dialogBox.ExtendedDialogTemplate.MenuResourceOrdinal} (0x{dialogBox.ExtendedDialogTemplate.MenuResourceOrdinal:X})" ) ;
builder . AppendLine ( $"{padding}Class resource: {dialogBox.ExtendedDialogTemplate.ClassResource ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( $"{padding}Class resource ordinal: {dialogBox.ExtendedDialogTemplate.ClassResourceOrdinal} (0x{dialogBox.ExtendedDialogTemplate.ClassResourceOrdinal:X})" ) ;
builder . AppendLine ( $"{padding}Title resource: {dialogBox.ExtendedDialogTemplate.TitleResource ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( $"{padding}Point size: {dialogBox.ExtendedDialogTemplate.PointSize} (0x{dialogBox.ExtendedDialogTemplate.PointSize:X})" ) ;
builder . AppendLine ( $"{padding}Weight: {dialogBox.ExtendedDialogTemplate.Weight} (0x{dialogBox.ExtendedDialogTemplate.Weight:X})" ) ;
builder . AppendLine ( $"{padding}Italic: {dialogBox.ExtendedDialogTemplate.Italic} (0x{dialogBox.ExtendedDialogTemplate.Italic:X})" ) ;
builder . AppendLine ( $"{padding}Character set: {dialogBox.ExtendedDialogTemplate.CharSet} (0x{dialogBox.ExtendedDialogTemplate.CharSet:X})" ) ;
builder . AppendLine ( $"{padding}Typeface: {dialogBox.ExtendedDialogTemplate.Typeface ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( ) ;
builder . AppendLine ( $"{padding}Dialog item templates" ) ;
builder . AppendLine ( $"{padding}-------------------------" ) ;
2022-12-08 14:00:29 -08:00
if ( dialogBox . ExtendedDialogTemplate . DialogItems = = 0
| | dialogBox . ExtendedDialogItemTemplates = = null
| | dialogBox . ExtendedDialogItemTemplates . Length = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}No dialog item templates" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
for ( int i = 0 ; i < dialogBox . ExtendedDialogItemTemplates . Length ; i + + )
{
var dialogItemTemplate = dialogBox . ExtendedDialogItemTemplates [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Dialog item template {i}" ) ;
builder . AppendLine ( $"{padding} Help ID: {dialogItemTemplate.HelpID} (0x{dialogItemTemplate.HelpID:X})" ) ;
builder . AppendLine ( $"{padding} Extended style: {dialogItemTemplate.ExtendedStyle} (0x{dialogItemTemplate.ExtendedStyle:X})" ) ;
builder . AppendLine ( $"{padding} Style: {dialogItemTemplate.Style} (0x{dialogItemTemplate.Style:X})" ) ;
builder . AppendLine ( $"{padding} X-coordinate of upper-left corner: {dialogItemTemplate.PositionX} (0x{dialogItemTemplate.PositionX:X})" ) ;
builder . AppendLine ( $"{padding} Y-coordinate of upper-left corner: {dialogItemTemplate.PositionY} (0x{dialogItemTemplate.PositionY:X})" ) ;
builder . AppendLine ( $"{padding} Width of the control: {dialogItemTemplate.WidthX} (0x{dialogItemTemplate.WidthX:X})" ) ;
builder . AppendLine ( $"{padding} Height of the control: {dialogItemTemplate.HeightY} (0x{dialogItemTemplate.HeightY:X})" ) ;
builder . AppendLine ( $"{padding} ID: {dialogItemTemplate.ID} (0x{dialogItemTemplate.ID:X})" ) ;
builder . AppendLine ( $"{padding} Class resource: {dialogItemTemplate.ClassResource ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( $"{padding} Class resource ordinal: {dialogItemTemplate.ClassResourceOrdinal} (0x{dialogItemTemplate.ClassResourceOrdinal:X})" ) ;
builder . AppendLine ( $"{padding} Title resource: {dialogItemTemplate.TitleResource ?? " [ EMPTY ] "}" ) ;
builder . AppendLine ( $"{padding} Title resource ordinal: {dialogItemTemplate.TitleResourceOrdinal} (0x{dialogItemTemplate.TitleResourceOrdinal:X})" ) ;
builder . AppendLine ( $"{padding} Creation data size: {dialogItemTemplate.CreationDataSize} (0x{dialogItemTemplate.CreationDataSize:X})" ) ;
2022-12-08 14:00:29 -08:00
if ( dialogItemTemplate . CreationData ! = null & & dialogItemTemplate . CreationData . Length ! = 0 )
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding} Creation data: {BitConverter.ToString(dialogItemTemplate.CreationData).Replace(" - ", string.Empty)}" ) ;
2022-12-08 14:00:29 -08:00
else
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding} Creation data: [EMPTY]" ) ;
2022-12-08 14:00:29 -08:00
}
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Dialog box resource found, but malformed" ) ;
2022-12-08 14:00:29 -08:00
}
}
/// <summary>
/// Print an RT_STRING resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_STRING ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
Dictionary < int , string > stringTable = null ;
try { stringTable = entry . AsStringTable ( ) ; } catch { }
if ( stringTable = = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}String table resource found, but malformed" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
foreach ( var kvp in stringTable )
{
int index = kvp . Key ;
string stringValue = kvp . Value ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}String entry {index}: {stringValue}" ) ;
2022-12-08 14:00:29 -08:00
}
}
/// <summary>
/// Print an RT_FONTDIR resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_FONTDIR ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Font directory resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_FONT resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_FONT ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Font resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_ACCELERATOR resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_ACCELERATOR ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
Models . PortableExecutable . AcceleratorTableEntry [ ] acceleratorTable = null ;
try { acceleratorTable = entry . AsAcceleratorTableResource ( ) ; } catch { }
if ( acceleratorTable = = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Accelerator table resource found, but malformed" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
for ( int i = 0 ; i < acceleratorTable . Length ; i + + )
{
var acceleratorTableEntry = acceleratorTable [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Accelerator Table Entry {i}:" ) ;
builder . AppendLine ( $"{padding} Flags: {acceleratorTableEntry.Flags} (0x{acceleratorTableEntry.Flags:X})" ) ;
builder . AppendLine ( $"{padding} Ansi: {acceleratorTableEntry.Ansi} (0x{acceleratorTableEntry.Ansi:X})" ) ;
builder . AppendLine ( $"{padding} Id: {acceleratorTableEntry.Id} (0x{acceleratorTableEntry.Id:X})" ) ;
builder . AppendLine ( $"{padding} Padding: {acceleratorTableEntry.Padding} (0x{acceleratorTableEntry.Padding:X})" ) ;
2022-12-08 14:00:29 -08:00
}
}
/// <summary>
/// Print an RT_RCDATA resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_RCDATA ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Application-defined resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
2022-12-13 21:05:52 -08:00
// Then print the data, if needed
2023-01-14 23:26:52 -08:00
if ( entry . Data = = null )
2022-12-13 21:05:52 -08:00
{
2023-01-14 23:26:52 -08:00
builder . AppendLine ( $"{padding}Data: [NULL] (This may indicate a very large resource)" ) ;
2022-12-13 21:05:52 -08:00
}
else
{
2023-01-14 23:26:52 -08:00
int offset = 0 ;
byte [ ] magic = entry . Data . ReadBytes ( ref offset , Math . Min ( entry . Data . Length , 16 ) ) ;
if ( entry . Data [ 0 ] = = 0x4D & & entry . Data [ 1 ] = = 0x5A )
{
builder . AppendLine ( $"{padding}Data: [Embedded Executable File]" ) ; // TODO: Parse this out and print separately
}
else if ( entry . Data [ 0 ] = = 0x4D & & entry . Data [ 1 ] = = 0x53 & & entry . Data [ 2 ] = = 0x46 & & entry . Data [ 3 ] = = 0x54 )
{
builder . AppendLine ( $"{padding}Data: [Embedded OLE Library File]" ) ; // TODO: Parse this out and print separately
}
else
{
builder . AppendLine ( $"{padding}Data: {BitConverter.ToString(magic).Replace('-', ' ')} ..." ) ;
//if (entry.Data != null)
// builder.AppendLine($"{padding}Value (Byte Data): {BitConverter.ToString(entry.Data).Replace('-', ' ')}");
//if (entry.Data != null)
// builder.AppendLine($"{padding}Value (ASCII): {Encoding.ASCII.GetString(entry.Data)}");
//if (entry.Data != null)
// builder.AppendLine($"{padding}Value (UTF-8): {Encoding.UTF8.GetString(entry.Data)}");
//if (entry.Data != null)
// builder.AppendLine($"{padding}Value (Unicode): {Encoding.Unicode.GetString(entry.Data)}");
}
2022-12-13 21:05:52 -08:00
}
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_MESSAGETABLE resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_MESSAGETABLE ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
Models . PortableExecutable . MessageResourceData messageTable = null ;
try { messageTable = entry . AsMessageResourceData ( ) ; } catch { }
if ( messageTable = = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Message resource data found, but malformed" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Number of blocks: {messageTable.NumberOfBlocks} (0x{messageTable.NumberOfBlocks:X})" ) ;
builder . AppendLine ( ) ;
builder . AppendLine ( $"{padding}Message resource blocks" ) ;
builder . AppendLine ( $"{padding}-------------------------" ) ;
2022-12-08 14:00:29 -08:00
if ( messageTable . NumberOfBlocks = = 0
| | messageTable . Blocks = = null
| | messageTable . Blocks . Length = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}No message resource blocks" ) ;
2022-12-08 14:00:29 -08:00
}
else
{
for ( int i = 0 ; i < messageTable . Blocks . Length ; i + + )
{
var messageResourceBlock = messageTable . Blocks [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Message resource block {i}" ) ;
builder . AppendLine ( $"{padding} Low ID: {messageResourceBlock.LowId} (0x{messageResourceBlock.LowId:X})" ) ;
builder . AppendLine ( $"{padding} High ID: {messageResourceBlock.HighId} (0x{messageResourceBlock.HighId:X})" ) ;
builder . AppendLine ( $"{padding} Offset to entries: {messageResourceBlock.OffsetToEntries} (0x{messageResourceBlock.OffsetToEntries:X})" ) ;
2022-12-08 14:00:29 -08:00
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( ) ;
2022-12-08 14:00:29 -08:00
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Message resource entries" ) ;
builder . AppendLine ( $"{padding}-------------------------" ) ;
2022-12-08 14:00:29 -08:00
if ( messageTable . Entries = = null
| | messageTable . Entries . Count = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}No message resource entries" ) ;
2022-12-08 14:00:29 -08:00
}
else
{
foreach ( var kvp in messageTable . Entries )
{
uint index = kvp . Key ;
var messageResourceEntry = kvp . Value ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Message resource entry {index}" ) ;
builder . AppendLine ( $"{padding} Length: {messageResourceEntry.Length} (0x{messageResourceEntry.Length:X})" ) ;
builder . AppendLine ( $"{padding} Flags: {messageResourceEntry.Flags} (0x{messageResourceEntry.Flags:X})" ) ;
builder . AppendLine ( $"{padding} Text: {messageResourceEntry.Text}" ) ;
2022-12-08 14:00:29 -08:00
}
}
}
/// <summary>
/// Print an RT_GROUP_CURSOR resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_GROUP_CURSOR ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Hardware-independent cursor resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_GROUP_ICON resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_GROUP_ICON ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Hardware-independent icon resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_VERSION resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_VERSION ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
Models . PortableExecutable . VersionInfo versionInfo = null ;
try { versionInfo = entry . AsVersionInfo ( ) ; } catch { }
if ( versionInfo = = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Version info resource found, but malformed" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Length: {versionInfo.Length} (0x{versionInfo.Length:X})" ) ;
builder . AppendLine ( $"{padding}Value length: {versionInfo.ValueLength} (0x{versionInfo.ValueLength:X})" ) ;
builder . AppendLine ( $"{padding}Resource type: {versionInfo.ResourceType} (0x{versionInfo.ResourceType:X})" ) ;
builder . AppendLine ( $"{padding}Key: {versionInfo.Key}" ) ;
2022-12-08 14:00:29 -08:00
if ( versionInfo . ValueLength ! = 0 & & versionInfo . Value ! = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[Fixed File Info] Signature: {versionInfo.Value.Signature} (0x{versionInfo.Value.Signature:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] Struct version: {versionInfo.Value.StrucVersion} (0x{versionInfo.Value.StrucVersion:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] File version (MS): {versionInfo.Value.FileVersionMS} (0x{versionInfo.Value.FileVersionMS:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] File version (LS): {versionInfo.Value.FileVersionLS} (0x{versionInfo.Value.FileVersionLS:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] Product version (MS): {versionInfo.Value.ProductVersionMS} (0x{versionInfo.Value.ProductVersionMS:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] Product version (LS): {versionInfo.Value.ProductVersionLS} (0x{versionInfo.Value.ProductVersionLS:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] File flags mask: {versionInfo.Value.FileFlagsMask} (0x{versionInfo.Value.FileFlagsMask:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] File flags: {versionInfo.Value.FileFlags} (0x{versionInfo.Value.FileFlags:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] File OS: {versionInfo.Value.FileOS} (0x{versionInfo.Value.FileOS:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] Type: {versionInfo.Value.FileType} (0x{versionInfo.Value.FileType:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] Subtype: {versionInfo.Value.FileSubtype} (0x{versionInfo.Value.FileSubtype:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] File date (MS): {versionInfo.Value.FileDateMS} (0x{versionInfo.Value.FileDateMS:X})" ) ;
builder . AppendLine ( $"{padding}[Fixed File Info] File date (LS): {versionInfo.Value.FileDateLS} (0x{versionInfo.Value.FileDateLS:X})" ) ;
2022-12-08 14:00:29 -08:00
}
if ( versionInfo . StringFileInfo ! = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[String File Info] Length: {versionInfo.StringFileInfo.Length} (0x{versionInfo.StringFileInfo.Length:X})" ) ;
builder . AppendLine ( $"{padding}[String File Info] Value length: {versionInfo.StringFileInfo.ValueLength} (0x{versionInfo.StringFileInfo.ValueLength:X})" ) ;
builder . AppendLine ( $"{padding}[String File Info] Resource type: {versionInfo.StringFileInfo.ResourceType} (0x{versionInfo.StringFileInfo.ResourceType:X})" ) ;
builder . AppendLine ( $"{padding}[String File Info] Key: {versionInfo.StringFileInfo.Key}" ) ;
builder . AppendLine ( $"{padding}Children:" ) ;
builder . AppendLine ( $"{padding}-------------------------" ) ;
2022-12-08 14:00:29 -08:00
if ( versionInfo . StringFileInfo . Children = = null | | versionInfo . StringFileInfo . Children . Length = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}No string file info children" ) ;
2022-12-08 14:00:29 -08:00
}
else
{
for ( int i = 0 ; i < versionInfo . StringFileInfo . Children . Length ; i + + )
{
var stringFileInfoChildEntry = versionInfo . StringFileInfo . Children [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding} [String Table {i}] Length: {stringFileInfoChildEntry.Length} (0x{stringFileInfoChildEntry.Length:X})" ) ;
builder . AppendLine ( $"{padding} [String Table {i}] Value length: {stringFileInfoChildEntry.ValueLength} (0x{stringFileInfoChildEntry.ValueLength:X})" ) ;
builder . AppendLine ( $"{padding} [String Table {i}] ResourceType: {stringFileInfoChildEntry.ResourceType} (0x{stringFileInfoChildEntry.ResourceType:X})" ) ;
builder . AppendLine ( $"{padding} [String Table {i}] Key: {stringFileInfoChildEntry.Key}" ) ;
builder . AppendLine ( $"{padding} [String Table {i}] Children:" ) ;
builder . AppendLine ( $"{padding} -------------------------" ) ;
2022-12-08 14:00:29 -08:00
if ( stringFileInfoChildEntry . Children = = null | | stringFileInfoChildEntry . Children . Length = = 0 )
2022-12-02 16:39:49 -08:00
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding} No string table {i} children" ) ;
2022-12-02 16:39:49 -08:00
}
else
{
2022-12-08 14:00:29 -08:00
for ( int j = 0 ; j < stringFileInfoChildEntry . Children . Length ; j + + )
2022-12-02 16:39:49 -08:00
{
2022-12-08 14:00:29 -08:00
var stringDataEntry = stringFileInfoChildEntry . Children [ j ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding} [String Data {j}] Length: {stringDataEntry.Length} (0x{stringDataEntry.Length:X})" ) ;
builder . AppendLine ( $"{padding} [String Data {j}] Value length: {stringDataEntry.ValueLength} (0x{stringDataEntry.ValueLength:X})" ) ;
builder . AppendLine ( $"{padding} [String Data {j}] ResourceType: {stringDataEntry.ResourceType} (0x{stringDataEntry.ResourceType:X})" ) ;
builder . AppendLine ( $"{padding} [String Data {j}] Key: {stringDataEntry.Key}" ) ;
builder . AppendLine ( $"{padding} [String Data {j}] Value: {stringDataEntry.Value}" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-08 14:00:29 -08:00
}
}
}
}
if ( versionInfo . VarFileInfo ! = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[Var File Info] Length: {versionInfo.VarFileInfo.Length} (0x{versionInfo.VarFileInfo.Length:X})" ) ;
builder . AppendLine ( $"{padding}[Var File Info] Value length: {versionInfo.VarFileInfo.ValueLength} (0x{versionInfo.VarFileInfo.ValueLength:X})" ) ;
builder . AppendLine ( $"{padding}[Var File Info] Resource type: {versionInfo.VarFileInfo.ResourceType} (0x{versionInfo.VarFileInfo.ResourceType:X})" ) ;
builder . AppendLine ( $"{padding}[Var File Info] Key: {versionInfo.VarFileInfo.Key}" ) ;
builder . AppendLine ( $"{padding}Children:" ) ;
builder . AppendLine ( $"{padding}-------------------------" ) ;
2022-12-08 14:00:29 -08:00
if ( versionInfo . VarFileInfo . Children = = null | | versionInfo . VarFileInfo . Children . Length = = 0 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}No var file info children" ) ;
2022-12-08 14:00:29 -08:00
}
else
{
for ( int i = 0 ; i < versionInfo . VarFileInfo . Children . Length ; i + + )
{
var varFileInfoChildEntry = versionInfo . VarFileInfo . Children [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding} [String Table {i}] Length: {varFileInfoChildEntry.Length} (0x{varFileInfoChildEntry.Length:X})" ) ;
builder . AppendLine ( $"{padding} [String Table {i}] Value length: {varFileInfoChildEntry.ValueLength} (0x{varFileInfoChildEntry.ValueLength:X})" ) ;
builder . AppendLine ( $"{padding} [String Table {i}] ResourceType: {varFileInfoChildEntry.ResourceType} (0x{varFileInfoChildEntry.ResourceType:X})" ) ;
builder . AppendLine ( $"{padding} [String Table {i}] Key: {varFileInfoChildEntry.Key}" ) ;
builder . AppendLine ( $"{padding} [String Table {i}] Value: {string.Join(" , ", varFileInfoChildEntry.Value)}" ) ;
2022-12-08 14:00:29 -08:00
}
}
}
}
/// <summary>
/// Print an RT_DLGINCLUDE resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_DLGINCLUDE ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}External header resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_PLUGPLAY resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_PLUGPLAY ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Plug and Play resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_VXD resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_VXD ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}VXD found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_ANICURSOR resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_ANICURSOR ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Animated cursor found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_ANIICON resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_ANIICON ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Animated icon found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_HTML resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_HTML ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}HTML resource found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
//if (entry.Data != null)
2023-01-13 14:04:21 -08:00
// builder.AppendLine($"{padding}Value (ASCII): {Encoding.ASCII.GetString(entry.Data)}");
2022-12-08 14:00:29 -08:00
//if (entry.Data != null)
2023-01-13 14:04:21 -08:00
// builder.AppendLine($"{padding}Value (UTF-8): {Encoding.UTF8.GetString(entry.Data)}");
2022-12-08 14:00:29 -08:00
//if (entry.Data != null)
2023-01-13 14:04:21 -08:00
// builder.AppendLine($"{padding}Value (Unicode): {Encoding.Unicode.GetString(entry.Data)}");
2022-12-08 14:00:29 -08:00
}
/// <summary>
/// Print an RT_MANIFEST resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceRT_MANIFEST ( Models . PortableExecutable . ResourceDataEntry entry , int level , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
Models . PortableExecutable . AssemblyManifest assemblyManifest = null ;
try { assemblyManifest = entry . AsAssemblyManifest ( ) ; } catch { }
if ( assemblyManifest = = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Assembly manifest found, but malformed" ) ;
2022-12-08 14:00:29 -08:00
return ;
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Manifest version: {assemblyManifest.ManifestVersion}" ) ;
2022-12-08 14:00:29 -08:00
if ( assemblyManifest . AssemblyIdentities ! = null & & assemblyManifest . AssemblyIdentities . Length > 0 )
{
for ( int i = 0 ; i < assemblyManifest . AssemblyIdentities . Length ; i + + )
{
var assemblyIdentity = assemblyManifest . AssemblyIdentities [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[Assembly Identity {i}] Name: {assemblyIdentity.Name}" ) ;
builder . AppendLine ( $"{padding}[Assembly Identity {i}] Version: {assemblyIdentity.Version}" ) ;
builder . AppendLine ( $"{padding}[Assembly Identity {i}] Type: {assemblyIdentity.Type}" ) ;
builder . AppendLine ( $"{padding}[Assembly Identity {i}] Processor architecture: {assemblyIdentity.ProcessorArchitecture}" ) ;
builder . AppendLine ( $"{padding}[Assembly Identity {i}] Public key token: {assemblyIdentity.PublicKeyToken}" ) ;
builder . AppendLine ( $"{padding}[Assembly Identity {i}] Language: {assemblyIdentity.Language}" ) ;
2022-12-08 14:00:29 -08:00
}
}
if ( assemblyManifest . Description ! = null )
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[Assembly Description] Value: {assemblyManifest.Description.Value}" ) ;
2022-12-08 14:00:29 -08:00
if ( assemblyManifest . COMInterfaceExternalProxyStub ! = null & & assemblyManifest . COMInterfaceExternalProxyStub . Length > 0 )
{
for ( int i = 0 ; i < assemblyManifest . COMInterfaceExternalProxyStub . Length ; i + + )
{
var comInterfaceExternalProxyStub = assemblyManifest . COMInterfaceExternalProxyStub [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[COM Interface External Proxy Stub {i}] IID: {comInterfaceExternalProxyStub.IID}" ) ;
builder . AppendLine ( $"{padding}[COM Interface External Proxy Stub {i}] Name: {comInterfaceExternalProxyStub.Name}" ) ;
builder . AppendLine ( $"{padding}[COM Interface External Proxy Stub {i}] TLBID: {comInterfaceExternalProxyStub.TLBID}" ) ;
builder . AppendLine ( $"{padding}[COM Interface External Proxy Stub {i}] Number of methods: {comInterfaceExternalProxyStub.NumMethods}" ) ;
builder . AppendLine ( $"{padding}[COM Interface External Proxy Stub {i}] Proxy stub (CLSID32): {comInterfaceExternalProxyStub.ProxyStubClsid32}" ) ;
builder . AppendLine ( $"{padding}[COM Interface External Proxy Stub {i}] Base interface: {comInterfaceExternalProxyStub.BaseInterface}" ) ;
2022-12-08 14:00:29 -08:00
}
}
if ( assemblyManifest . Dependency ! = null & & assemblyManifest . Dependency . Length > 0 )
{
for ( int i = 0 ; i < assemblyManifest . Dependency . Length ; i + + )
{
var dependency = assemblyManifest . Dependency [ i ] ;
if ( dependency . DependentAssembly ! = null )
{
if ( dependency . DependentAssembly . AssemblyIdentity ! = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[Dependency {i} Assembly Identity] Name: {dependency.DependentAssembly.AssemblyIdentity.Name}" ) ;
builder . AppendLine ( $"{padding}[Dependency {i} Assembly Identity] Version: {dependency.DependentAssembly.AssemblyIdentity.Version}" ) ;
builder . AppendLine ( $"{padding}[Dependency {i} Assembly Identity] Type: {dependency.DependentAssembly.AssemblyIdentity.Type}" ) ;
builder . AppendLine ( $"{padding}[Dependency {i} Assembly Identity] Processor architecture: {dependency.DependentAssembly.AssemblyIdentity.ProcessorArchitecture}" ) ;
builder . AppendLine ( $"{padding}[Dependency {i} Assembly Identity] Public key token: {dependency.DependentAssembly.AssemblyIdentity.PublicKeyToken}" ) ;
builder . AppendLine ( $"{padding}[Dependency {i} Assembly Identity] Language: {dependency.DependentAssembly.AssemblyIdentity.Language}" ) ;
2022-12-08 14:00:29 -08:00
}
if ( dependency . DependentAssembly . BindingRedirect ! = null & & dependency . DependentAssembly . BindingRedirect . Length > 0 )
{
for ( int j = 0 ; j < dependency . DependentAssembly . BindingRedirect . Length ; j + + )
2022-12-02 16:39:49 -08:00
{
2022-12-08 14:00:29 -08:00
var bindingRedirect = dependency . DependentAssembly . BindingRedirect [ j ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[Dependency {i} Binding Redirect {j}] Old version: {bindingRedirect.OldVersion}" ) ;
builder . AppendLine ( $"{padding}[Dependency {i} Binding Redirect {j}] New version: {bindingRedirect.NewVersion}" ) ;
2022-12-02 16:39:49 -08:00
}
2022-12-08 14:00:29 -08:00
}
}
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[Dependency {i}] Optional: {dependency.Optional}" ) ;
2022-12-08 14:00:29 -08:00
}
}
if ( assemblyManifest . File ! = null & & assemblyManifest . File . Length > 0 )
{
for ( int i = 0 ; i < assemblyManifest . File . Length ; i + + )
{
var file = assemblyManifest . File [ i ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[File {i}] Name: {file.Name}" ) ;
builder . AppendLine ( $"{padding}[File {i}] Hash: {file.Hash}" ) ;
builder . AppendLine ( $"{padding}[File {i}] Hash algorithm: {file.HashAlgorithm}" ) ;
builder . AppendLine ( $"{padding}[File {i}] Size: {file.Size}" ) ;
2022-12-08 14:00:29 -08:00
if ( file . COMClass ! = null & & file . COMClass . Length > 0 )
{
for ( int j = 0 ; j < file . COMClass . Length ; j + + )
{
var comClass = file . COMClass [ j ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[File {i} COM Class {j}] CLSID: {comClass.CLSID}" ) ;
builder . AppendLine ( $"{padding}[File {i} COM Class {j}] Threading model: {comClass.ThreadingModel}" ) ;
builder . AppendLine ( $"{padding}[File {i} COM Class {j}] Prog ID: {comClass.ProgID}" ) ;
builder . AppendLine ( $"{padding}[File {i} COM Class {j}] TLBID: {comClass.TLBID}" ) ;
builder . AppendLine ( $"{padding}[File {i} COM Class {j}] Description: {comClass.Description}" ) ;
2022-12-08 14:00:29 -08:00
if ( comClass . ProgIDs ! = null & & comClass . ProgIDs . Length > 0 )
2022-12-02 16:39:49 -08:00
{
2022-12-08 14:00:29 -08:00
for ( int k = 0 ; k < comClass . ProgIDs . Length ; k + + )
2022-12-02 16:39:49 -08:00
{
2022-12-08 14:00:29 -08:00
var progId = comClass . ProgIDs [ k ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[File {i} COM Class {j} Prog ID {k}] Value: {progId.Value}" ) ;
2022-12-02 16:39:49 -08:00
}
}
}
2022-12-08 14:00:29 -08:00
}
if ( file . COMInterfaceProxyStub ! = null & & file . COMInterfaceProxyStub . Length > 0 )
{
for ( int j = 0 ; j < file . COMInterfaceProxyStub . Length ; j + + )
{
var comInterfaceProxyStub = file . COMInterfaceProxyStub [ j ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[File {i} COM Interface Proxy Stub {j}] IID: {comInterfaceProxyStub.IID}" ) ;
builder . AppendLine ( $"{padding}[File {i} COM Interface Proxy Stub {j}] Name: {comInterfaceProxyStub.Name}" ) ;
builder . AppendLine ( $"{padding}[File {i} COM Interface Proxy Stub {j}] TLBID: {comInterfaceProxyStub.TLBID}" ) ;
builder . AppendLine ( $"{padding}[File {i} COM Interface Proxy Stub {j}] Number of methods: {comInterfaceProxyStub.NumMethods}" ) ;
builder . AppendLine ( $"{padding}[File {i} COM Interface Proxy Stub {j}] Proxy stub (CLSID32): {comInterfaceProxyStub.ProxyStubClsid32}" ) ;
builder . AppendLine ( $"{padding}[File {i} COM Interface Proxy Stub {j}] Base interface: {comInterfaceProxyStub.BaseInterface}" ) ;
2022-12-08 14:00:29 -08:00
}
}
if ( file . Typelib ! = null & & file . Typelib . Length > 0 )
{
for ( int j = 0 ; j < file . Typelib . Length ; j + + )
{
var typeLib = file . Typelib [ j ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[File {i} Type Lib {j}] TLBID: {typeLib.TLBID}" ) ;
builder . AppendLine ( $"{padding}[File {i} Type Lib {j}] Version: {typeLib.Version}" ) ;
builder . AppendLine ( $"{padding}[File {i} Type Lib {j}] Help directory: {typeLib.HelpDir}" ) ;
builder . AppendLine ( $"{padding}[File {i} Type Lib {j}] Resource ID: {typeLib.ResourceID}" ) ;
builder . AppendLine ( $"{padding}[File {i} Type Lib {j}] Flags: {typeLib.Flags}" ) ;
2022-12-08 14:00:29 -08:00
}
}
if ( file . WindowClass ! = null & & file . WindowClass . Length > 0 )
{
for ( int j = 0 ; j < file . WindowClass . Length ; j + + )
{
var windowClass = file . WindowClass [ j ] ;
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}[File {i} Window Class {j}] Versioned: {windowClass.Versioned}" ) ;
builder . AppendLine ( $"{padding}[File {i} Window Class {j}] Value: {windowClass.Value}" ) ;
2022-12-08 14:00:29 -08:00
}
}
2022-12-02 16:39:49 -08:00
}
}
2022-12-08 14:00:29 -08:00
if ( assemblyManifest . EverythingElse ! = null & & assemblyManifest . EverythingElse . Length > 0 )
2022-12-02 16:39:49 -08:00
{
2022-12-08 14:00:29 -08:00
for ( int i = 0 ; i < assemblyManifest . EverythingElse . Length ; i + + )
{
var thing = assemblyManifest . EverythingElse [ i ] ;
if ( thing is XmlElement element )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Unparsed XML Element {i}: {element.OuterXml}" ) ;
2022-12-08 14:00:29 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Unparsed Item {i}: {thing}" ) ;
2022-12-08 14:00:29 -08:00
}
}
}
}
/// <summary>
/// Print an UNKNOWN or custom resource
/// </summary>
2023-01-13 14:04:21 -08:00
/// <param name="builder">StringBuilder to append information to</param>
private static void PrintResourceUNKNOWN ( Models . PortableExecutable . ResourceDataEntry entry , int level , object resourceType , StringBuilder builder )
2022-12-08 14:00:29 -08:00
{
string padding = new string ( ' ' , ( level + 1 ) * 2 ) ;
2022-12-08 16:40:04 -08:00
// Print the type first
2022-12-08 14:00:29 -08:00
if ( resourceType is uint numericType )
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Type {(Models.PortableExecutable.ResourceType)numericType} found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
else if ( resourceType is string stringType )
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Type {stringType} found, not parsed yet" ) ;
2022-12-08 16:40:04 -08:00
else
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Unknown type {resourceType} found, not parsed yet" ) ;
2022-12-08 14:00:29 -08:00
2022-12-08 16:40:04 -08:00
// Then print the data, if needed
2023-01-03 22:32:22 -08:00
if ( entry . Data = = null )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Data: [NULL] (This may indicate a very large resource)" ) ;
2023-01-03 22:32:22 -08:00
}
2022-12-08 14:00:29 -08:00
else
{
2023-01-04 20:29:41 -08:00
int offset = 0 ;
byte [ ] magic = entry . Data . ReadBytes ( ref offset , Math . Min ( entry . Data . Length , 16 ) ) ;
if ( entry . Data [ 0 ] = = 0x4D & & entry . Data [ 1 ] = = 0x5A )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Data: [Embedded Executable File]" ) ; // TODO: Parse this out and print separately
2023-01-04 20:29:41 -08:00
}
else if ( entry . Data [ 0 ] = = 0x4D & & entry . Data [ 1 ] = = 0x53 & & entry . Data [ 2 ] = = 0x46 & & entry . Data [ 3 ] = = 0x54 )
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Data: [Embedded OLE Library File]" ) ; // TODO: Parse this out and print separately
2023-01-04 20:29:41 -08:00
}
else
{
2023-01-13 14:04:21 -08:00
builder . AppendLine ( $"{padding}Data: {BitConverter.ToString(magic).Replace('-', ' ')} ..." ) ;
2023-01-04 20:29:41 -08:00
//if (entry.Data != null)
2023-01-13 14:04:21 -08:00
// builder.AppendLine($"{padding}Value (Byte Data): {BitConverter.ToString(entry.Data).Replace('-', ' ')}");
2023-01-04 20:29:41 -08:00
//if (entry.Data != null)
2023-01-13 14:04:21 -08:00
// builder.AppendLine($"{padding}Value (ASCII): {Encoding.ASCII.GetString(entry.Data)}");
2023-01-04 20:29:41 -08:00
//if (entry.Data != null)
2023-01-13 14:04:21 -08:00
// builder.AppendLine($"{padding}Value (UTF-8): {Encoding.UTF8.GetString(entry.Data)}");
2023-01-04 20:29:41 -08:00
//if (entry.Data != null)
2023-01-13 14:04:21 -08:00
// builder.AppendLine($"{padding}Value (Unicode): {Encoding.Unicode.GetString(entry.Data)}");
2023-01-04 20:29:41 -08:00
}
2022-12-02 16:39:49 -08:00
}
}
2022-12-02 21:20:52 -08:00
2023-01-13 10:41:50 -08:00
#if NET6_0_OR_GREATER
/// <inheritdoc/>
public override string ExportJSON ( ) = > System . Text . Json . JsonSerializer . Serialize ( _executable , _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>
public IEnumerable < object > FindCodeViewDebugTableByPath ( string path )
{
// Ensure that we have the debug data cached
if ( DebugData = = null )
return Enumerable . Empty < object > ( ) ;
2022-12-14 21:30:53 -08:00
var nb10Found = DebugData . Select ( r = > r . Value )
2023-03-08 17:49:14 -05:00
. Select ( r = > r as Models . PortableExecutable . NB10ProgramDatabase )
2022-12-14 21:07:02 -08:00
. Where ( n = > n ! = null )
2022-12-14 21:30:53 -08:00
. Where ( n = > n . PdbFileName . Contains ( path ) )
. Select ( n = > ( object ) n ) ;
var rsdsFound = DebugData . Select ( r = > r . Value )
2023-03-08 17:49:14 -05:00
. Select ( r = > r as Models . PortableExecutable . RSDSProgramDatabase )
2022-12-14 21:30:53 -08:00
. Where ( r = > r ! = null )
. Where ( r = > r . PathAndFileName . Contains ( path ) )
. Select ( r = > ( object ) r ) ;
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>
2022-12-14 21:07:02 -08:00
public IEnumerable < byte [ ] > FindGenericDebugTableByValue ( string value )
2022-12-14 20:46:24 -08:00
{
// Ensure that we have the resource data cached
if ( DebugData = = null )
return Enumerable . Empty < byte [ ] > ( ) ;
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
{
string arrayAsASCII = Encoding . ASCII . GetString ( b ) ;
if ( arrayAsASCII . Contains ( value ) )
return true ;
}
catch { }
try
{
string arrayAsUTF8 = Encoding . UTF8 . GetString ( b ) ;
if ( arrayAsUTF8 . Contains ( value ) )
return true ;
}
catch { }
try
{
string arrayAsUnicode = Encoding . Unicode . GetString ( b ) ;
if ( arrayAsUnicode . Contains ( value ) )
return true ;
}
catch { }
return false ;
} ) ;
}
#endregion
#region Debug Parsing
/// <summary>
/// Parse the debug directory table information
/// </summary>
private void ParseDebugTable ( )
{
// Loop through all debug table entries
for ( int i = 0 ; i < DebugTable . DebugDirectoryTable . Length ; i + + )
{
var entry = DebugTable . DebugDirectoryTable [ i ] ;
uint address = entry . PointerToRawData ;
uint size = entry . SizeOfData ;
byte [ ] entryData = ReadFromDataSource ( ( int ) address , ( int ) size ) ;
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
if ( entry . DebugType = = Models . PortableExecutable . DebugType . IMAGE_DEBUG_TYPE_CODEVIEW )
{
// 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>
public IEnumerable < Models . PortableExecutable . DialogBoxResource > FindDialogByTitle ( string title )
{
2022-12-03 22:55:03 -08:00
// Ensure that we have the resource data cached
if ( ResourceData = = null )
return Enumerable . Empty < Models . PortableExecutable . DialogBoxResource > ( ) ;
2022-12-03 20:56:06 -08:00
return ResourceData . Select ( r = > r . Value )
2023-03-08 17:49:14 -05:00
. Select ( r = > r as Models . PortableExecutable . DialogBoxResource )
2022-12-03 20:56:06 -08:00
. Where ( d = > d ! = null )
. Where ( d = >
{
return ( d . DialogTemplate ? . TitleResource ? . Contains ( title ) ? ? false )
| | ( d . ExtendedDialogTemplate ? . TitleResource ? . Contains ( title ) ? ? false ) ;
} ) ;
}
/// <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>
public IEnumerable < Models . PortableExecutable . DialogBoxResource > FindDialogBoxByItemTitle ( string title )
{
2022-12-03 22:55:03 -08:00
// Ensure that we have the resource data cached
if ( ResourceData = = null )
return Enumerable . Empty < Models . PortableExecutable . DialogBoxResource > ( ) ;
2022-12-03 20:56:06 -08:00
return ResourceData . Select ( r = > r . Value )
2023-03-08 17:49:14 -05:00
. Select ( r = > r as Models . PortableExecutable . DialogBoxResource )
2022-12-03 20:56:06 -08:00
. Where ( d = > d ! = null )
. Where ( d = >
{
if ( d . DialogItemTemplates ! = null )
{
return d . DialogItemTemplates
. Where ( dit = > dit ? . TitleResource ! = null )
. Any ( dit = > dit . TitleResource . Contains ( title ) ) ;
}
else if ( d . ExtendedDialogItemTemplates ! = null )
{
return d . ExtendedDialogItemTemplates
. Where ( edit = > edit ? . TitleResource ! = null )
. Any ( edit = > edit . TitleResource . Contains ( title ) ) ;
}
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>
public IEnumerable < Dictionary < int , string > > FindStringTableByEntry ( string entry )
{
// Ensure that we have the resource data cached
if ( ResourceData = = null )
return Enumerable . Empty < Dictionary < int , string > > ( ) ;
return ResourceData . Select ( r = > r . Value )
. Select ( r = > r as Dictionary < int , string > )
. Where ( st = > st ! = null )
. Where ( st = > st . Select ( kvp = > kvp . Value )
. Any ( s = > s . Contains ( entry ) ) ) ;
}
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>
public IEnumerable < byte [ ] > FindResourceByNamedType ( string typeName )
{
2022-12-03 22:55:03 -08:00
// Ensure that we have the resource data cached
if ( ResourceData = = null )
return Enumerable . Empty < byte [ ] > ( ) ;
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>
public IEnumerable < byte [ ] > FindGenericResource ( string value )
{
2022-12-03 22:55:03 -08:00
// Ensure that we have the resource data cached
if ( ResourceData = = null )
return Enumerable . Empty < byte [ ] > ( ) ;
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
{
string arrayAsASCII = Encoding . ASCII . GetString ( b ) ;
if ( arrayAsASCII . Contains ( value ) )
return true ;
}
catch { }
try
{
string arrayAsUTF8 = Encoding . UTF8 . GetString ( b ) ;
if ( arrayAsUTF8 . Contains ( value ) )
return true ;
}
catch { }
try
{
string arrayAsUnicode = Encoding . Unicode . GetString ( b ) ;
if ( arrayAsUnicode . Contains ( value ) )
return true ;
}
catch { }
2022-12-03 22:55:03 -08:00
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>
private void ParseResourceDirectoryTable ( Models . PortableExecutable . ResourceDirectoryTable table , List < object > types )
{
2022-12-30 09:09:42 -08:00
int totalEntries = table ? . Entries ? . Length ? ? 0 ;
2022-12-03 14:22:54 -08:00
for ( int i = 0 ; i < totalEntries ; i + + )
{
var entry = table . Entries [ i ] ;
var newTypes = new List < object > ( types ? ? new List < object > ( ) ) ;
if ( entry . Name ! = null )
newTypes . Add ( Encoding . UTF8 . GetString ( entry . Name . UnicodeString ? ? new byte [ 0 ] ) ) ;
else
newTypes . Add ( entry . IntegerID ) ;
ParseResourceDirectoryEntry ( entry , newTypes ) ;
}
}
/// <summary>
/// Parse the name resource directory entry information
/// </summary>
private void ParseResourceDirectoryEntry ( Models . PortableExecutable . ResourceDirectoryEntry entry , List < object > types )
{
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>
private void ParseResourceDataEntry ( Models . PortableExecutable . ResourceDataEntry entry , List < object > types )
{
// Create the key and value objects
string key = types = = null ? $"UNKNOWN_{Guid.NewGuid()}" : string . Join ( ", " , types ) ;
object value = entry . Data ;
// If we have a known resource type
if ( types ! = null & & types . Count > 0 & & types [ 0 ] is uint resourceType )
{
2022-12-03 22:55:03 -08:00
try
2022-12-03 14:22:54 -08:00
{
2022-12-03 22:55:03 -08:00
switch ( ( Models . PortableExecutable . ResourceType ) resourceType )
{
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_CURSOR :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_BITMAP :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_ICON :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_MENU :
2022-12-03 22:55:03 -08:00
value = entry . AsMenu ( ) ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_DIALOG :
2022-12-03 22:55:03 -08:00
value = entry . AsDialogBox ( ) ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_STRING :
2022-12-03 22:55:03 -08:00
value = entry . AsStringTable ( ) ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_FONTDIR :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_FONT :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_ACCELERATOR :
2022-12-03 22:55:03 -08:00
value = entry . AsAcceleratorTableResource ( ) ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_RCDATA :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_MESSAGETABLE :
2022-12-03 22:55:03 -08:00
value = entry . AsMessageResourceData ( ) ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_GROUP_CURSOR :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_GROUP_ICON :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_VERSION :
2022-12-03 22:55:03 -08:00
_versionInfo = entry . AsVersionInfo ( ) ;
value = _versionInfo ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_DLGINCLUDE :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_PLUGPLAY :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_VXD :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_ANICURSOR :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_ANIICON :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_HTML :
2022-12-03 22:55:03 -08:00
value = entry . Data ;
break ;
2023-03-08 17:49:14 -05:00
case Models . PortableExecutable . ResourceType . RT_MANIFEST :
2022-12-03 22:55:03 -08:00
_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>
public bool ContainsSection ( string sectionName , bool exact = false )
{
// 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 ( )
{
// If we don't have an entry point
if ( OH_AddressOfEntryPoint . ConvertVirtualAddress ( SectionTable ) = = 0 )
return - 1 ;
// Otherwise, find the section it exists within
return OH_AddressOfEntryPoint . ContainingSectionIndex ( SectionTable ) ;
}
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-03-08 17:49:14 -05:00
public Models . PortableExecutable . SectionHeader GetFirstSection ( string name , bool exact = false )
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 ( ! 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-03-08 17:49:14 -05:00
public Models . PortableExecutable . SectionHeader GetLastSection ( string name , bool exact = false )
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 ( ! 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-03-08 17:49:14 -05:00
public Models . PortableExecutable . SectionHeader GetSection ( int index )
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>
public byte [ ] GetFirstSectionData ( string name , bool exact = false )
{
// 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 ( ! ContainsSection ( name , exact ) )
return null ;
2022-12-03 21:37:32 -08:00
// 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 21:37:32 -08:00
}
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>
public byte [ ] GetLastSectionData ( string name , bool exact = false )
{
// 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 ( ! 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>
public byte [ ] GetSectionData ( int index )
{
// 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 ;
// Get the section data from the table
2022-12-05 11:01:22 -08:00
var section = SectionTable [ index ] ;
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 ;
2022-12-03 21:37:32 -08:00
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
2022-12-03 21:37:32 -08:00
if ( _sectionData [ index ] ! = null )
2022-12-03 20:56:06 -08:00
return _sectionData [ index ] ;
// Populate the raw section data based on the source
byte [ ] sectionData = ReadFromDataSource ( ( int ) address , ( int ) size ) ;
// 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>
public List < string > GetFirstSectionStrings ( string name , bool exact = false )
{
// If we have no sections
if ( SectionTable = = null | | ! SectionTable . Any ( ) )
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>
public List < string > GetLastSectionStrings ( string name , bool exact = false )
{
// If we have no sections
if ( SectionTable = = null | | ! SectionTable . Any ( ) )
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>
public List < string > GetSectionStrings ( int index )
{
// If we have no sections
if ( SectionTable = = null | | ! SectionTable . Any ( ) )
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 ] ;
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
List < string > sectionStringData = ReadStringsFromDataSource ( ( int ) address , ( int ) size ) ;
// 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>
public byte [ ] GetTableData ( int index )
{
// 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 :
virtualAddress = OH_ExportTable . VirtualAddress ;
size = OH_ExportTable . Size ;
break ;
case 2 :
virtualAddress = OH_ImportTable . VirtualAddress ;
size = OH_ImportTable . Size ;
break ;
case 3 :
virtualAddress = OH_ResourceTable . VirtualAddress ;
size = OH_ResourceTable . Size ;
break ;
case 4 :
virtualAddress = OH_ExceptionTable . VirtualAddress ;
size = OH_ExceptionTable . Size ;
break ;
case 5 :
virtualAddress = OH_CertificateTable . VirtualAddress ;
size = OH_CertificateTable . Size ;
break ;
case 6 :
virtualAddress = OH_BaseRelocationTable . VirtualAddress ;
size = OH_BaseRelocationTable . Size ;
break ;
case 7 :
virtualAddress = OH_Debug . VirtualAddress ;
size = OH_Debug . Size ;
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 :
virtualAddress = OH_GlobalPtr . VirtualAddress ;
size = OH_GlobalPtr . Size ;
break ;
case 10 :
virtualAddress = OH_ThreadLocalStorageTable . VirtualAddress ;
size = OH_ThreadLocalStorageTable . Size ;
break ;
case 11 :
virtualAddress = OH_LoadConfigTable . VirtualAddress ;
size = OH_LoadConfigTable . Size ;
break ;
case 12 :
virtualAddress = OH_BoundImport . VirtualAddress ;
size = OH_BoundImport . Size ;
break ;
case 13 :
virtualAddress = OH_ImportAddressTable . VirtualAddress ;
size = OH_ImportAddressTable . Size ;
break ;
case 14 :
virtualAddress = OH_DelayImportDescriptor . VirtualAddress ;
size = OH_DelayImportDescriptor . Size ;
break ;
case 15 :
virtualAddress = OH_CLRRuntimeHeader . VirtualAddress ;
size = OH_CLRRuntimeHeader . Size ;
break ;
case 16 : // Reserved
virtualAddress = 0 ;
size = 0 ;
break ;
}
// 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
byte [ ] tableData = ReadFromDataSource ( ( int ) address , ( int ) size ) ;
// 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>
public List < string > GetTableStrings ( int index )
{
// 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 :
virtualAddress = OH_ExportTable . VirtualAddress ;
size = OH_ExportTable . Size ;
break ;
case 2 :
virtualAddress = OH_ImportTable . VirtualAddress ;
size = OH_ImportTable . Size ;
break ;
case 3 :
virtualAddress = OH_ResourceTable . VirtualAddress ;
size = OH_ResourceTable . Size ;
break ;
case 4 :
virtualAddress = OH_ExceptionTable . VirtualAddress ;
size = OH_ExceptionTable . Size ;
break ;
case 5 :
virtualAddress = OH_CertificateTable . VirtualAddress ;
size = OH_CertificateTable . Size ;
break ;
case 6 :
virtualAddress = OH_BaseRelocationTable . VirtualAddress ;
size = OH_BaseRelocationTable . Size ;
break ;
case 7 :
virtualAddress = OH_Debug . VirtualAddress ;
size = OH_Debug . Size ;
break ;
case 8 : // Architecture Table
virtualAddress = 0 ;
size = 0 ;
break ;
case 9 :
virtualAddress = OH_GlobalPtr . VirtualAddress ;
size = OH_GlobalPtr . Size ;
break ;
case 10 :
virtualAddress = OH_ThreadLocalStorageTable . VirtualAddress ;
size = OH_ThreadLocalStorageTable . Size ;
break ;
case 11 :
virtualAddress = OH_LoadConfigTable . VirtualAddress ;
size = OH_LoadConfigTable . Size ;
break ;
case 12 :
virtualAddress = OH_BoundImport . VirtualAddress ;
size = OH_BoundImport . Size ;
break ;
case 13 :
virtualAddress = OH_ImportAddressTable . VirtualAddress ;
size = OH_ImportAddressTable . Size ;
break ;
case 14 :
virtualAddress = OH_DelayImportDescriptor . VirtualAddress ;
size = OH_DelayImportDescriptor . Size ;
break ;
case 15 :
virtualAddress = OH_CLRRuntimeHeader . VirtualAddress ;
size = OH_CLRRuntimeHeader . Size ;
break ;
case 16 : // Reserved
virtualAddress = 0 ;
size = 0 ;
break ;
}
// 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
List < string > tableStringData = ReadStringsFromDataSource ( ( int ) address , ( int ) size ) ;
// Cache and return the table string data, even if null
_tableStringData [ index ] = tableStringData ;
return tableStringData ;
}
}
#endregion
2022-12-02 15:20:44 -08:00
}
}