using System; using System.Collections.Generic; using System.Text; using System.Xml; using SabreTools.Data.Extensions; using SabreTools.Data.Models.COFF; using SabreTools.Data.Models.COFF.SymbolTableEntries; using SabreTools.Data.Models.PortableExecutable; using SabreTools.Data.Models.PortableExecutable.Resource.Entries; using SabreTools.IO.Extensions; using SabreTools.Matching; using SabreTools.Numerics.Extensions; using SabreTools.Text.Extensions; namespace SabreTools.Wrappers { public partial class PortableExecutable : IPrintable { #if NETCOREAPP /// public string ExportJSON() => System.Text.Json.JsonSerializer.Serialize(Model, _jsonSerializerOptions); #endif /// public void PrintInformation(StringBuilder builder) { builder.AppendLine("Portable Executable Information:"); builder.AppendLine("-------------------------"); builder.AppendLine(); // Stub Print(builder, Model.Stub.Header); // Header Print(builder, Model.Signature, Model.FileHeader); Print(builder, Model.OptionalHeader, Model.SectionTable); // COFF Tables Print(builder, Model.SectionTable); Print(builder, Model.SymbolTable); Print(builder, Model.StringTable); // Export Table Print(builder, Model.ExportDirectoryTable, Model.SectionTable); Print(builder, Model.ExportAddressTable, Model.SectionTable); Print(builder, Model.NamePointerTable); Print(builder, Model.OrdinalTable); Print(builder, Model.ExportNameTable); // Import Table Print(builder, Model.ImportDirectoryTable, Model.SectionTable); Print(builder, Model.ImportLookupTables, Model.SectionTable); Print(builder, Model.ImportAddressTables, Model.SectionTable); Print(builder, Model.HintNameTable); // Resource Table Print(builder, Model.ResourceDirectoryTable, Model.SectionTable); Print(builder, Model.AttributeCertificateTable); Print(builder, Model.DelayLoadDirectoryTable, Model.SectionTable); // Named Sections Print(builder, Model.BaseRelocationTable, Model.SectionTable); Print(builder, Model.DebugTable); } private static void Print(StringBuilder builder, Data.Models.MSDOS.ExecutableHeader header) { builder.AppendLine(" MS-DOS Stub Header Information:"); builder.AppendLine(" -------------------------"); builder.AppendLine(header.Magic, " Magic number"); builder.AppendLine(header.LastPageBytes, " Last page bytes"); builder.AppendLine(header.Pages, " Pages"); builder.AppendLine(header.RelocationItems, " Relocation items"); builder.AppendLine(header.HeaderParagraphSize, " Header paragraph size"); builder.AppendLine(header.MinimumExtraParagraphs, " Minimum extra paragraphs"); builder.AppendLine(header.MaximumExtraParagraphs, " Maximum extra paragraphs"); builder.AppendLine(header.InitialSSValue, " Initial SS value"); builder.AppendLine(header.InitialSPValue, " Initial SP value"); builder.AppendLine(header.Checksum, " Checksum"); builder.AppendLine(header.InitialIPValue, " Initial IP value"); builder.AppendLine(header.InitialCSValue, " Initial CS value"); builder.AppendLine(header.RelocationTableAddr, " Relocation table address"); builder.AppendLine(header.OverlayNumber, " Overlay number"); builder.AppendLine(); builder.AppendLine(" MS-DOS Stub Extended Header Information:"); builder.AppendLine(" -------------------------"); builder.AppendLine(header.Reserved1, " Reserved words"); builder.AppendLine(header.OEMIdentifier, " OEM identifier"); builder.AppendLine(header.OEMInformation, " OEM information"); builder.AppendLine(header.Reserved2, " Reserved words"); builder.AppendLine(header.NewExeHeaderAddr, " New EXE header address"); builder.AppendLine(); } private static void Print(StringBuilder builder, string? signature, FileHeader header) { builder.AppendLine(" File Header Information:"); builder.AppendLine(" -------------------------"); builder.AppendLine(signature, " Signature"); builder.AppendLine($" Machine: {header.Machine} (0x{header.Machine:X})"); builder.AppendLine(header.NumberOfSections, " Number of sections"); builder.AppendLine(header.TimeDateStamp, " Time/Date stamp"); builder.AppendLine(header.PointerToSymbolTable, " Pointer to symbol table"); builder.AppendLine(header.NumberOfSymbols, " Number of symbols"); builder.AppendLine(header.SizeOfOptionalHeader, " Size of optional header"); builder.AppendLine($" Characteristics: {header.Characteristics} (0x{header.Characteristics:X})"); builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.OptionalHeader header, SectionHeader[] table) { builder.AppendLine(" Optional Header Information:"); builder.AppendLine(" -------------------------"); builder.AppendLine($" Magic: {header.Magic} (0x{header.Magic:X})"); builder.AppendLine(header.MajorLinkerVersion, " Major linker version"); builder.AppendLine(header.MinorLinkerVersion, " Minor linker version"); builder.AppendLine(header.SizeOfCode, " Size of code section"); builder.AppendLine(header.SizeOfInitializedData, " Size of initialized data"); builder.AppendLine(header.SizeOfUninitializedData, " Size of uninitialized data"); builder.AppendLine(header.AddressOfEntryPoint, " Address of entry point"); builder.AppendLine(header.BaseOfCode, " Base of code"); if (header.Magic == OptionalHeaderMagicNumber.PE32) builder.AppendLine(header.BaseOfData, " Base of data"); builder.AppendLine(header.ImageBase, " Image base"); builder.AppendLine(header.SectionAlignment, " Section alignment"); builder.AppendLine(header.FileAlignment, " File alignment"); builder.AppendLine(header.MajorOperatingSystemVersion, " Major operating system version"); builder.AppendLine(header.MinorOperatingSystemVersion, " Minor operating system version"); builder.AppendLine(header.MajorImageVersion, " Major image version"); builder.AppendLine(header.MinorImageVersion, " Minor image version"); builder.AppendLine(header.MajorSubsystemVersion, " Major subsystem version"); builder.AppendLine(header.MinorSubsystemVersion, " Minor subsystem version"); builder.AppendLine(header.Win32VersionValue, " Win32 version value"); builder.AppendLine(header.SizeOfImage, " Size of image"); builder.AppendLine(header.SizeOfHeaders, " Size of headers"); builder.AppendLine(header.CheckSum, " Checksum"); builder.AppendLine($" Subsystem: {header.Subsystem} (0x{header.Subsystem:X})"); builder.AppendLine($" DLL characteristics: {header.DllCharacteristics} (0x{header.DllCharacteristics:X})"); builder.AppendLine(header.SizeOfStackReserve, " Size of stack reserve"); builder.AppendLine(header.SizeOfStackCommit, " Size of stack commit"); builder.AppendLine(header.SizeOfHeapReserve, " Size of heap reserve"); builder.AppendLine(header.SizeOfHeapCommit, " Size of heap commit"); builder.AppendLine(header.LoaderFlags, " Loader flags"); builder.AppendLine(header.NumberOfRvaAndSizes, " Number of data-directory entries"); if (header.ExportTable is not null) { builder.AppendLine(" Export Table (1)"); builder.AppendLine(header.ExportTable.VirtualAddress, " Virtual address"); builder.AppendLine(header.ExportTable.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.ExportTable.Size, " Size"); } if (header.ImportTable is not null) { builder.AppendLine(" Import Table (2)"); builder.AppendLine(header.ImportTable.VirtualAddress, " Virtual address"); builder.AppendLine(header.ImportTable.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.ImportTable.Size, " Size"); } if (header.ResourceTable is not null) { builder.AppendLine(" Resource Table (3)"); builder.AppendLine(header.ResourceTable.VirtualAddress, " Virtual address"); builder.AppendLine(header.ResourceTable.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.ResourceTable.Size, " Size"); } if (header.ExceptionTable is not null) { builder.AppendLine(" Exception Table (4)"); builder.AppendLine(header.ExceptionTable.VirtualAddress, " Virtual address"); builder.AppendLine(header.ExceptionTable.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.ExceptionTable.Size, " Size"); } if (header.CertificateTable is not null) { builder.AppendLine(" Certificate Table (5)"); builder.AppendLine(" Virtual address: N/A"); builder.AppendLine(header.CertificateTable.VirtualAddress, " Physical address"); builder.AppendLine(header.CertificateTable.Size, " Size"); } if (header.BaseRelocationTable is not null) { builder.AppendLine(" Base Relocation Table (6)"); builder.AppendLine(header.BaseRelocationTable.VirtualAddress, " Virtual address"); builder.AppendLine(header.BaseRelocationTable.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.BaseRelocationTable.Size, " Size"); } if (header.Debug is not null) { builder.AppendLine(" Debug Table (7)"); builder.AppendLine(header.Debug.VirtualAddress, " Virtual address"); builder.AppendLine(header.Debug.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.Debug.Size, " Size"); } if (header.NumberOfRvaAndSizes >= 8) { builder.AppendLine(" Architecture Table (8)"); builder.AppendLine(" Virtual address: 0 (0x00000000)"); builder.AppendLine(" Physical address: 0 (0x00000000)"); builder.AppendLine(" Size: 0 (0x00000000)"); } if (header.GlobalPtr is not null) { builder.AppendLine(" Global Pointer Register (9)"); builder.AppendLine(header.GlobalPtr.VirtualAddress, " Virtual address"); builder.AppendLine(header.GlobalPtr.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.GlobalPtr.Size, " Size"); } if (header.ThreadLocalStorageTable is not null) { builder.AppendLine(" Thread Local Storage (TLS) Table (10)"); builder.AppendLine(header.ThreadLocalStorageTable.VirtualAddress, " Virtual address"); builder.AppendLine(header.ThreadLocalStorageTable.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.ThreadLocalStorageTable.Size, " Size"); } if (header.LoadConfigTable is not null) { builder.AppendLine(" Load Config Table (11)"); builder.AppendLine(header.LoadConfigTable.VirtualAddress, " Virtual address"); builder.AppendLine(header.LoadConfigTable.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.LoadConfigTable.Size, " Size"); } if (header.BoundImport is not null) { builder.AppendLine(" Bound Import Table (12)"); builder.AppendLine(header.BoundImport.VirtualAddress, " Virtual address"); builder.AppendLine(header.BoundImport.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.BoundImport.Size, " Size"); } if (header.ImportAddressTable is not null) { builder.AppendLine(" Import Address Table (13)"); builder.AppendLine(header.ImportAddressTable.VirtualAddress, " Virtual address"); builder.AppendLine(header.ImportAddressTable.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.ImportAddressTable.Size, " Size"); } if (header.DelayImportDescriptor is not null) { builder.AppendLine(" Delay Import Descriptor (14)"); builder.AppendLine(header.DelayImportDescriptor.VirtualAddress, " Virtual address"); builder.AppendLine(header.DelayImportDescriptor.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.DelayImportDescriptor.Size, " Size"); } if (header.CLRRuntimeHeader is not null) { builder.AppendLine(" CLR Runtime Header (15)"); builder.AppendLine(header.CLRRuntimeHeader.VirtualAddress, " Virtual address"); builder.AppendLine(header.CLRRuntimeHeader.VirtualAddress.ConvertVirtualAddress(table), " Physical address"); builder.AppendLine(header.CLRRuntimeHeader.Size, " Size"); } if (header.NumberOfRvaAndSizes >= 16) { builder.AppendLine(" Reserved (16)"); builder.AppendLine(" Virtual address: 0 (0x00000000)"); builder.AppendLine(" Physical address: 0 (0x00000000)"); builder.AppendLine(" Size: 0 (0x00000000)"); } builder.AppendLine(); } private static void Print(StringBuilder builder, SectionHeader[] entries) { builder.AppendLine(" Section Table Information:"); builder.AppendLine(" -------------------------"); if (entries is null || entries.Length == 0) { builder.AppendLine(" No section table items"); builder.AppendLine(); return; } for (int i = 0; i < entries!.Length; i++) { var entry = entries[i]; builder.AppendLine($" Section Table Entry {i}"); builder.AppendLine(entry.Name, " Name", Encoding.ASCII); builder.AppendLine(entry.VirtualSize, " Virtual size"); builder.AppendLine(entry.VirtualAddress, " Virtual address"); builder.AppendLine(entry.VirtualAddress.ConvertVirtualAddress(entries), " Physical address"); builder.AppendLine(entry.SizeOfRawData, " Size of raw data"); builder.AppendLine(entry.PointerToRawData, " Pointer to raw data"); builder.AppendLine(entry.PointerToRelocations, " Pointer to relocations"); builder.AppendLine(entry.PointerToLinenumbers, " Pointer to linenumbers"); builder.AppendLine(entry.NumberOfRelocations, " Number of relocations"); builder.AppendLine(entry.NumberOfLinenumbers, " Number of linenumbers"); builder.AppendLine($" Characteristics: {entry.Characteristics} (0x{entry.Characteristics:X})"); // TODO: Add COFFRelocations // TODO: Add COFFLineNumbers } builder.AppendLine(); } private static void Print(StringBuilder builder, BaseEntry[]? entries) { builder.AppendLine(" Symbol Table Information:"); builder.AppendLine(" -------------------------"); if (entries is null || entries.Length == 0) { builder.AppendLine(" No symbol table items"); builder.AppendLine(); return; } for (int i = 0; i < entries.Length; i++) { var entry = entries[i]; switch (entry) { case StandardRecord item: Print(builder, item, i); break; case FunctionDefinition item: Print(builder, item, i); break; case Descriptor item: Print(builder, item, i); break; case WeakExternal item: Print(builder, item, i); break; case FileRecord item: Print(builder, item, i); break; case SectionDefinition item: Print(builder, item, i); break; case CLRTokenDefinition item: Print(builder, item, i); break; default: break; } } builder.AppendLine(); } private static void Print(StringBuilder builder, StandardRecord entry, int i) { builder.AppendLine($" Symbol Table Entry {i} (Standard Record)"); if (entry.ShortName is not null) { builder.AppendLine(entry.ShortName, " Short name", Encoding.ASCII); } else { builder.AppendLine(entry.Zeroes, " Zeroes"); builder.AppendLine(entry.Offset, " Offset"); } builder.AppendLine(entry.Value, " Value"); 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(entry.NumberOfAuxSymbols, " Number of aux symbols"); } private static void Print(StringBuilder builder, FunctionDefinition entry, int i) { builder.AppendLine($" Symbol Table Entry {i} (Function Definition)"); builder.AppendLine(entry.TagIndex, " Tag index"); builder.AppendLine(entry.TotalSize, " Total size"); builder.AppendLine(entry.PointerToLinenumber, " Pointer to linenumber"); builder.AppendLine(entry.PointerToNextFunction, " Pointer to next function"); builder.AppendLine(entry.Unused, " Unused"); } private static void Print(StringBuilder builder, Descriptor entry, int i) { builder.AppendLine($" Symbol Table Entry {i} (.bf and .ef Symbol)"); builder.AppendLine(entry.Unused1, " Unused"); builder.AppendLine(entry.Linenumber, " Linenumber"); builder.AppendLine(entry.Unused2, " Unused"); builder.AppendLine(entry.PointerToNextFunction, " Pointer to next function"); builder.AppendLine(entry.Unused3, " Unused"); } private static void Print(StringBuilder builder, WeakExternal entry, int i) { builder.AppendLine($" Symbol Table Entry {i} (Weak External)"); builder.AppendLine(entry.TagIndex, " Tag index"); builder.AppendLine(entry.Characteristics, " Characteristics"); builder.AppendLine(entry.Unused, " Unused"); } private static void Print(StringBuilder builder, FileRecord entry, int i) { builder.AppendLine($" Symbol Table Entry {i} (File)"); builder.AppendLine(entry.FileName, " File name", Encoding.ASCII); } private static void Print(StringBuilder builder, SectionDefinition entry, int i) { builder.AppendLine($" Symbol Table Entry {i} (Section Defintion)"); builder.AppendLine(entry.Length, " Length"); builder.AppendLine(entry.NumberOfRelocations, " Number of relocations"); builder.AppendLine(entry.NumberOfLinenumbers, " Number of linenumbers"); builder.AppendLine(entry.CheckSum, " Checksum"); builder.AppendLine(entry.Number, " Number"); builder.AppendLine(entry.Selection, " Selection"); builder.AppendLine(entry.Unused, " Unused"); } private static void Print(StringBuilder builder, CLRTokenDefinition entry, int i) { builder.AppendLine($" Symbol Table Entry {i} (CLR Token Defintion)"); builder.AppendLine(entry.AuxType, " Aux type"); builder.AppendLine(entry.Reserved1, " Reserved"); builder.AppendLine(entry.SymbolTableIndex, " Symbol table index"); builder.AppendLine(entry.Reserved2, " Reserved"); } private static void Print(StringBuilder builder, Data.Models.COFF.StringTable? stringTable) { builder.AppendLine(" String Table Information:"); builder.AppendLine(" -------------------------"); if (stringTable?.Strings is null || stringTable.Strings.Length == 0) { builder.AppendLine(" No string table items"); builder.AppendLine(); return; } builder.AppendLine(stringTable.TotalSize, " Total size"); for (int i = 0; i < stringTable.Strings.Length; i++) { string? entry = stringTable.Strings[i]; builder.AppendLine($" String Table Entry {i})"); builder.AppendLine(entry, " Value"); } builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.AttributeCertificate.Entry[]? entries) { builder.AppendLine(" Attribute Certificate Table Information:"); builder.AppendLine(" -------------------------"); if (entries is null || entries.Length == 0) { builder.AppendLine(" No attribute certificate table items"); builder.AppendLine(); return; } // Create the deserializer var deserializer = new Serialization.Readers.AbstractSyntaxNotationOne(); for (int i = 0; i < entries.Length; i++) { var entry = entries[i]; builder.AppendLine($" Attribute Certificate Table Entry {i}"); builder.AppendLine(entry.Length, " Length"); builder.AppendLine($" Revision: {entry.Revision} (0x{entry.Revision:X})"); builder.AppendLine($" Certificate type: {entry.CertificateType} (0x{entry.CertificateType:X})"); builder.AppendLine(); if (entry.CertificateType == WindowsCertificateType.WIN_CERT_TYPE_PKCS_SIGNED_DATA) { builder.AppendLine(" Certificate Data [Formatted]"); builder.AppendLine(" -------------------------"); if (entry.Certificate is null) { builder.AppendLine(" INVALID DATA FOUND"); } else { var topLevelValues = deserializer.Deserialize(entry.Certificate, 0); if (topLevelValues is null) { builder.AppendLine(" INVALID DATA FOUND"); builder.AppendLine(entry.Certificate, " Raw data"); } else { foreach (Data.Models.ASN1.TypeLengthValue tlv in topLevelValues) { string tlvString = tlv.Format(paddingLevel: 4); builder.AppendLine(tlvString); } } } } else { builder.AppendLine(" Certificate Data [Binary]"); builder.AppendLine(" -------------------------"); try { builder.AppendLine(entry.Certificate, " Raw data"); } catch { builder.AppendLine(" [DATA TOO LARGE TO FORMAT]"); } } builder.AppendLine(); } } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.DelayLoad.DirectoryTable? table, SectionHeader[] sections) { builder.AppendLine(" Delay-Load Directory Table Information:"); builder.AppendLine(" -------------------------"); if (table is null) { builder.AppendLine(" No delay-load directory table items"); builder.AppendLine(); return; } builder.AppendLine(table.Attributes, " Attributes"); builder.AppendLine(table.NameRVA, " Name RVA"); builder.AppendLine(table.NameRVA.ConvertVirtualAddress(sections), " Name physical address"); builder.AppendLine(table.ModuleHandle, " Module handle"); builder.AppendLine(table.DelayImportAddressTable, " Delay import address table RVA"); builder.AppendLine(table.DelayImportAddressTable.ConvertVirtualAddress(sections), " Delay import address table physical address"); builder.AppendLine(table.DelayImportNameTable, " Delay import name table RVA"); builder.AppendLine(table.DelayImportNameTable.ConvertVirtualAddress(sections), " Delay import name table physical address"); builder.AppendLine(table.BoundDelayImportTable, " Bound delay import table RVA"); builder.AppendLine(table.BoundDelayImportTable.ConvertVirtualAddress(sections), " Bound delay import table physical address"); builder.AppendLine(table.UnloadDelayImportTable, " Unload delay import table RVA"); builder.AppendLine(table.UnloadDelayImportTable.ConvertVirtualAddress(sections), " Unload delay import table physical address"); builder.AppendLine(table.TimeStamp, " Timestamp"); builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.BaseRelocation.Block[]? entries, SectionHeader[] sections) { builder.AppendLine(" Base Relocation Table Information:"); builder.AppendLine(" -------------------------"); if (entries is null || entries.Length == 0) { builder.AppendLine(" No base relocation table items"); builder.AppendLine(); return; } for (int i = 0; i < entries.Length; i++) { var baseRelocationTableEntry = entries[i]; builder.AppendLine($" Base Relocation Table Entry {i}"); builder.AppendLine(baseRelocationTableEntry.PageRVA, " Page RVA"); builder.AppendLine(baseRelocationTableEntry.PageRVA.ConvertVirtualAddress(sections), " Page physical address"); builder.AppendLine(baseRelocationTableEntry.BlockSize, " Block size"); builder.AppendLine(); builder.AppendLine($" Base Relocation Table {i} Type and Offset Information:"); builder.AppendLine(" -------------------------"); if (baseRelocationTableEntry.TypeOffsetFieldEntries.Length == 0) { builder.AppendLine(" No base relocation table type and offset entries"); builder.AppendLine(); continue; } for (int j = 0; j < baseRelocationTableEntry.TypeOffsetFieldEntries.Length; j++) { var typeOffsetFieldEntry = baseRelocationTableEntry.TypeOffsetFieldEntries[j]; builder.AppendLine($" Type and Offset Entry {j}"); builder.AppendLine($" Type: {typeOffsetFieldEntry.BaseRelocationType} (0x{typeOffsetFieldEntry.BaseRelocationType:X})"); builder.AppendLine(typeOffsetFieldEntry.Offset, " Offset"); } } builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.DebugData.Table? table) { builder.AppendLine(" Debug Table Information:"); builder.AppendLine(" -------------------------"); if (table?.DebugDirectoryTable is null || table.DebugDirectoryTable.Length == 0) { builder.AppendLine(" No debug table items"); builder.AppendLine(); return; } for (int i = 0; i < table.DebugDirectoryTable.Length; i++) { var entry = table.DebugDirectoryTable[i]; builder.AppendLine($" Debug Directory Table Entry {i}"); builder.AppendLine(entry.Characteristics, " Characteristics"); builder.AppendLine(entry.TimeDateStamp, " Time/Date stamp"); builder.AppendLine(entry.MajorVersion, " Major version"); builder.AppendLine(entry.MinorVersion, " Minor version"); builder.AppendLine($" Debug type: {entry.DebugType} (0x{entry.DebugType:X})"); builder.AppendLine(entry.SizeOfData, " Size of data"); builder.AppendLine(entry.AddressOfRawData, " Address of raw data"); builder.AppendLine(entry.PointerToRawData, " Pointer to raw data"); } builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Export.DirectoryTable? table, SectionHeader[] sections) { builder.AppendLine(value: " Export Directory Table Information:"); builder.AppendLine(" -------------------------"); if (table is null) { builder.AppendLine(" No export directory table"); } else { builder.AppendLine(table.ExportFlags, " Export flags"); builder.AppendLine(table.TimeDateStamp, " Time/Date stamp"); builder.AppendLine(table.MajorVersion, " Major version"); builder.AppendLine(table.MinorVersion, " Minor version"); builder.AppendLine(table.NameRVA, " Name RVA"); builder.AppendLine(table.NameRVA.ConvertVirtualAddress(sections), " Name physical address"); builder.AppendLine(table.Name, " Name"); builder.AppendLine(table.OrdinalBase, " Ordinal base"); builder.AppendLine(table.AddressTableEntries, " Address table entries"); builder.AppendLine(table.NumberOfNamePointers, " Number of name pointers"); builder.AppendLine(table.ExportAddressTableRVA, " Export address table RVA"); builder.AppendLine(table.ExportAddressTableRVA.ConvertVirtualAddress(sections), " Export address table physical address"); builder.AppendLine(table.NamePointerRVA, " Name pointer table RVA"); builder.AppendLine(table.NamePointerRVA.ConvertVirtualAddress(sections), " Name pointer table physical address"); builder.AppendLine(table.OrdinalTableRVA, " Ordinal table RVA"); builder.AppendLine(table.OrdinalTableRVA.ConvertVirtualAddress(sections), " Ordinal table physical address"); } builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Export.AddressTableEntry[]? table, SectionHeader[] sections) { builder.AppendLine(" Export Address Table Information:"); builder.AppendLine(" -------------------------"); if (table is null || table.Length == 0) { builder.AppendLine(" No export address table items"); } else { for (int i = 0; i < table.Length; i++) { var entry = table[i]; builder.AppendLine($" Export Address Table Entry {i}"); builder.AppendLine(entry.ExportRVA, " Export / Forwarder RVA"); builder.AppendLine(entry.ExportRVA.ConvertVirtualAddress(sections), " Export / Forwarder physical address"); } } builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Export.NamePointerTable? table) { builder.AppendLine(" Export Name Pointer Table Information:"); builder.AppendLine(" -------------------------"); if (table?.Pointers is null || table.Pointers.Length == 0) { builder.AppendLine(" No export name pointer table items"); } else { for (int i = 0; i < table.Pointers.Length; i++) { var entry = table.Pointers[i]; builder.AppendLine($" Export Name Pointer Table Entry {i}"); builder.AppendLine(entry, " Pointer"); } } builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Export.OrdinalTable? table) { builder.AppendLine(" Export Ordinal Table Information:"); builder.AppendLine(" -------------------------"); if (table?.Indexes is null || table.Indexes.Length == 0) { builder.AppendLine(" No export ordinal table items"); } else { for (int i = 0; i < table.Indexes.Length; i++) { var entry = table.Indexes[i]; builder.AppendLine($" Export Ordinal Table Entry {i}"); builder.AppendLine(entry, " Index"); } } builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Export.NameTable? table) { builder.AppendLine(" Export Name Table Information:"); builder.AppendLine(" -------------------------"); if (table?.Strings is null || table.Strings.Length == 0) { builder.AppendLine(" No export name table items"); } else { for (int i = 0; i < table.Strings.Length; i++) { var entry = table.Strings[i]; builder.AppendLine($" Export Name Table Entry {i}"); builder.AppendLine(entry, " String"); } } builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Import.DirectoryTableEntry[]? table, SectionHeader[] sections) { builder.AppendLine(" Import Directory Table Information:"); builder.AppendLine(" -------------------------"); if (table is null || table.Length == 0) { builder.AppendLine(" No import directory table items"); } else { for (int i = 0; i < table.Length; i++) { var entry = table[i]; builder.AppendLine($" Import Directory Table Entry {i}"); builder.AppendLine(entry.ImportLookupTableRVA, " Import lookup table RVA"); builder.AppendLine(entry.ImportLookupTableRVA.ConvertVirtualAddress(sections), " Import lookup table physical address"); builder.AppendLine(entry.TimeDateStamp, " Time/Date stamp"); builder.AppendLine(entry.ForwarderChain, " Forwarder chain"); builder.AppendLine(entry.NameRVA, " Name RVA"); builder.AppendLine(entry.NameRVA.ConvertVirtualAddress(sections), " Name physical address"); builder.AppendLine(entry.Name, " Name"); builder.AppendLine(entry.ImportAddressTableRVA, " Import address table RVA"); builder.AppendLine(entry.ImportAddressTableRVA.ConvertVirtualAddress(sections), " Import address table physical address"); } } builder.AppendLine(); } private static void Print(StringBuilder builder, Dictionary? tables, SectionHeader[] sections) { builder.AppendLine(" Import Lookup Tables Information:"); builder.AppendLine(" -------------------------"); if (tables is null || tables.Count == 0) { builder.AppendLine(" No import lookup tables"); } else { foreach (var kvp in tables) { int index = kvp.Key; var importLookupTable = kvp.Value; builder.AppendLine(); builder.AppendLine($" Import Lookup Table {index} Information:"); builder.AppendLine(" -------------------------"); if (importLookupTable is null || importLookupTable.Length == 0) { builder.AppendLine(" No import lookup table items"); continue; } for (int i = 0; i < importLookupTable.Length; i++) { var entry = importLookupTable[i]; builder.AppendLine($" Import Lookup Table {index} Entry {i}"); builder.AppendLine(entry.OrdinalNameFlag, " Ordinal/Name flag"); if (entry.OrdinalNameFlag) { builder.AppendLine(entry.OrdinalNumber, " Ordinal number"); } else { builder.AppendLine(entry.HintNameTableRVA, " Hint/Name table RVA"); builder.AppendLine(entry.HintNameTableRVA.ConvertVirtualAddress(sections), " Hint/Name table physical address"); } } } } builder.AppendLine(); } private static void Print(StringBuilder builder, Dictionary? tables, SectionHeader[] sections) { builder.AppendLine(" Import Address Tables Information:"); builder.AppendLine(" -------------------------"); if (tables is null || tables.Count == 0) { builder.AppendLine(" No import address tables"); } else { foreach (var kvp in tables) { int index = kvp.Key; var importAddressTable = kvp.Value; builder.AppendLine(); builder.AppendLine($" Import Address Table {index} Information:"); builder.AppendLine(" -------------------------"); if (importAddressTable is null || importAddressTable.Length == 0) { builder.AppendLine(" No import address table items"); continue; } for (int i = 0; i < importAddressTable.Length; i++) { var entry = importAddressTable[i]; builder.AppendLine($" Import Address Table {index} Entry {i}"); builder.AppendLine(entry.OrdinalNameFlag, " Ordinal/Name flag"); if (entry.OrdinalNameFlag) { builder.AppendLine(entry.OrdinalNumber, " Ordinal number"); } else { builder.AppendLine(entry.HintNameTableRVA, " Hint/Name table RVA"); builder.AppendLine(entry.HintNameTableRVA.ConvertVirtualAddress(sections), " Hint/Name table physical address"); } } } } builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Import.HintNameTableEntry[]? table) { builder.AppendLine(" Import Hint/Name Table Information:"); builder.AppendLine(" -------------------------"); if (table is null || table.Length == 0) { builder.AppendLine(" No import hint/name table items"); } else { for (int i = 0; i < table.Length; i++) { var entry = table[i]; builder.AppendLine($" Hint/Name Table Entry {i}"); builder.AppendLine(entry.Hint, " Hint"); builder.AppendLine(entry.Name, " Name"); } } builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Resource.DirectoryTable? table, SectionHeader[] sections) { builder.AppendLine(" Resource Directory Table Information:"); builder.AppendLine(" -------------------------"); if (table is null) { builder.AppendLine(" No resource directory table items"); builder.AppendLine(); return; } Print(builder, table, level: 0, types: [], sections); builder.AppendLine(); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Resource.DirectoryTable table, int level, List types, SectionHeader[] sections) { string padding = new(' ', (level + 1) * 2); builder.AppendLine(level, $"{padding}Table level"); builder.AppendLine(table.Characteristics, $"{padding}Characteristics"); builder.AppendLine(table.TimeDateStamp, $"{padding}Time/Date stamp"); builder.AppendLine(table.MajorVersion, $"{padding}Major version"); builder.AppendLine(table.MinorVersion, $"{padding}Minor version"); builder.AppendLine(table.NumberOfNameEntries, $"{padding}Number of name entries"); builder.AppendLine(table.NumberOfIDEntries, $"{padding}Number of ID entries"); builder.AppendLine(); builder.AppendLine($"{padding}Entries"); builder.AppendLine($"{padding}-------------------------"); if (table.NumberOfNameEntries == 0 && table.NumberOfIDEntries == 0) { builder.AppendLine($"{padding}No entries"); builder.AppendLine(); } else { for (int i = 0; i < table.Entries.Length; i++) { var entry = table.Entries[i]; var newTypes = new List(types ?? []); if (entry.Name?.UnicodeString is not null) newTypes.Add(Encoding.Unicode.GetString(entry.Name.UnicodeString)); else newTypes.Add(entry.IntegerID); Print(builder, entry, level + 1, newTypes, sections); } } } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Resource.DirectoryEntry entry, int level, List types, SectionHeader[] sections) { string padding = new(' ', (level + 1) * 2); builder.AppendLine(level, $"{padding}Item level"); if (entry.NameOffset != default) { builder.AppendLine(entry.NameOffset, $"{padding}Name offset"); builder.AppendLine(entry.Name?.UnicodeString, $"{padding}Name ({entry.Name?.Length ?? 0})", Encoding.Unicode); } else { builder.AppendLine(entry.IntegerID, $"{padding}Integer ID"); } if (entry.DataEntry is not null) Print(builder, entry.DataEntry, level: level + 1, types, sections); else if (entry.Subdirectory is not null) Print(builder, entry.Subdirectory, level: level + 1, types, sections); } private static void Print(StringBuilder builder, Data.Models.PortableExecutable.Resource.DataEntry entry, int level, List types, SectionHeader[] sections) { string padding = new(' ', (level + 1) * 2); // TODO: Use ordered list of base types to determine the shape of the data var baseTypes = Array.ConvertAll(types.ToArray(), t => t.ToString()); builder.AppendLine($"{padding}Base types: {string.Join(", ", baseTypes)}"); builder.AppendLine(level, $"{padding}Entry level"); builder.AppendLine(entry.DataRVA, $"{padding}Data RVA"); builder.AppendLine(entry.DataRVA.ConvertVirtualAddress(sections), $"{padding}Data physical address"); builder.AppendLine(entry.Size, $"{padding}Size"); builder.AppendLine(entry.Codepage, $"{padding}Codepage"); builder.AppendLine(entry.Reserved, $"{padding}Reserved"); // TODO: Print out per-type data if (types is not null && types.Count > 0 && types[0] is uint resourceType) { switch ((ResourceType)resourceType) { case ResourceType.RT_CURSOR: PrintResourceRT_CURSOR(entry, level, builder); break; case ResourceType.RT_BITMAP: case ResourceType.RT_NEWBITMAP: PrintResourceRT_BITMAP(entry, level, builder); break; case ResourceType.RT_ICON: PrintResourceRT_ICON(entry, level, builder); break; case ResourceType.RT_MENU: case ResourceType.RT_NEWMENU: PrintResourceRT_MENU(entry, level, builder); break; case ResourceType.RT_DIALOG: case ResourceType.RT_NEWDIALOG: PrintResourceRT_DIALOG(entry, level, builder); break; case ResourceType.RT_STRING: PrintResourceRT_STRING(entry, level, builder); break; case ResourceType.RT_FONTDIR: PrintResourceRT_FONTDIR(entry, level, builder); break; case ResourceType.RT_FONT: PrintResourceRT_FONT(entry, level, builder); break; case ResourceType.RT_ACCELERATOR: PrintResourceRT_ACCELERATOR(entry, level, builder); break; case ResourceType.RT_RCDATA: PrintResourceRT_RCDATA(entry, level, builder); break; case ResourceType.RT_MESSAGETABLE: PrintResourceRT_MESSAGETABLE(entry, level, builder); break; case ResourceType.RT_GROUP_CURSOR: PrintResourceRT_GROUP_CURSOR(entry, level, builder); break; case ResourceType.RT_GROUP_ICON: PrintResourceRT_GROUP_ICON(entry, level, builder); break; case ResourceType.RT_VERSION: PrintResourceRT_VERSION(entry, level, builder); break; case ResourceType.RT_DLGINCLUDE: PrintResourceRT_DLGINCLUDE(entry, level, builder); break; case ResourceType.RT_PLUGPLAY: PrintResourceRT_PLUGPLAY(entry, level, builder); break; case ResourceType.RT_VXD: PrintResourceRT_VXD(entry, level, builder); break; case ResourceType.RT_ANICURSOR: PrintResourceRT_ANICURSOR(entry, level, builder); break; case ResourceType.RT_ANIICON: PrintResourceRT_ANIICON(entry, level, builder); break; case ResourceType.RT_HTML: PrintResourceRT_HTML(entry, level, builder); break; case ResourceType.RT_MANIFEST: PrintResourceRT_MANIFEST(entry, level, builder); break; // Bitflag, ignore case ResourceType.RT_NEWRESOURCE: break; // Error state, ignore case ResourceType.RT_ERROR: PrintResourceUNKNOWN(entry, level, types[0], builder); break; default: PrintResourceUNKNOWN(entry, level, types[0], builder); break; } } else if (types is not null && types.Count > 0 && types[0] is string resourceString) { PrintResourceUNKNOWN(entry, level, types[0], builder); } builder.AppendLine(); } private static void PrintResourceRT_CURSOR(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Hardware-dependent cursor resource found, not parsed yet"); } private static void PrintResourceRT_BITMAP(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Bitmap resource found, not parsed yet"); } private static void PrintResourceRT_ICON(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Hardware-dependent icon resource found, not parsed yet"); } private static void PrintResourceRT_MENU(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); MenuResource? menu = null; try { menu = Serialization.Readers.PortableExecutable.ParseMenuResource(entry.Data); } catch { } if (menu is null) { builder.AppendLine($"{padding}Menu resource found, but malformed"); return; } if (menu.MenuHeader is NormalMenuHeader normalMenuHeader) { builder.AppendLine(normalMenuHeader.Version, $"{padding}Version"); builder.AppendLine(normalMenuHeader.HeaderSize, $"{padding}Header size"); } else if (menu.MenuHeader is MenuHeaderExtended menuHeaderExtended) { builder.AppendLine(menuHeaderExtended.Version, $"{padding}Version"); builder.AppendLine(menuHeaderExtended.Offset, $"{padding}Offset"); builder.AppendLine(menuHeaderExtended.HelpID, $"{padding}Help ID"); } else { builder.AppendLine($"{padding}Menu header found, but malformed"); } builder.AppendLine(); builder.AppendLine($"{padding}Menu items"); builder.AppendLine($"{padding}-------------------------"); if (menu.MenuItems.Length == 0) { builder.AppendLine($"{padding}No menu items"); return; } for (int i = 0; i < menu.MenuItems.Length; i++) { var menuItem = menu.MenuItems[i]; builder.AppendLine($"{padding}Menu item {i}"); if (menuItem is null) { builder.AppendLine($"{padding} [NULL]"); continue; } if (menuItem is NormalMenuItem normalMenuItem) { builder.AppendLine($"{padding} Resource info: {normalMenuItem.NormalResInfo} (0x{normalMenuItem.NormalResInfo:X})"); builder.AppendLine(normalMenuItem.NormalMenuText, $"{padding} Menu text"); } else if (menuItem is PopupMenuItem popupMenuItem) { builder.AppendLine($"{padding} Item type: {popupMenuItem.PopupItemType} (0x{popupMenuItem.PopupItemType:X})"); builder.AppendLine($"{padding} State: {popupMenuItem.PopupState} (0x{popupMenuItem.PopupState:X})"); builder.AppendLine(popupMenuItem.PopupID, $"{padding} ID"); builder.AppendLine($"{padding} Resource info: {popupMenuItem.PopupResInfo} (0x{popupMenuItem.PopupResInfo:X})"); builder.AppendLine(popupMenuItem.PopupMenuText, $"{padding} Menu text"); } else if (menuItem is MenuItemExtended menuItemExtended) { builder.AppendLine($"{padding} Item type: {menuItemExtended.ItemType} (0x{menuItemExtended.ItemType:X})"); builder.AppendLine($"{padding} State: {menuItemExtended.State} (0x{menuItemExtended.State:X})"); builder.AppendLine(menuItemExtended.ID, $"{padding} ID"); builder.AppendLine($"{padding} Flags: {menuItemExtended.Flags} (0x{menuItemExtended.Flags:X})"); builder.AppendLine(menuItemExtended.MenuText, $"{padding} Menu text"); } else { builder.AppendLine($"{padding} Menu item found, but malformed"); } } } private static void PrintResourceRT_DIALOG(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); DialogBoxResource? dialogBox = null; try { dialogBox = Serialization.Readers.PortableExecutable.ParseDialogBoxResource(entry.Data); } catch { } if (dialogBox is null) { builder.AppendLine($"{padding}Dialog box resource found, but malformed"); return; } if (dialogBox.DialogTemplate is not null) { 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(dialogBox.DialogTemplate.ItemCount, $"{padding}Item count"); builder.AppendLine(dialogBox.DialogTemplate.PositionX, $"{padding}X-coordinate of upper-left corner"); builder.AppendLine(dialogBox.DialogTemplate.PositionY, $"{padding}Y-coordinate of upper-left corner"); builder.AppendLine(dialogBox.DialogTemplate.WidthX, $"{padding}Width of the dialog box"); builder.AppendLine(dialogBox.DialogTemplate.HeightY, $"{padding}Height of the dialog box"); builder.AppendLine(dialogBox.DialogTemplate.MenuResource, $"{padding}Menu resource"); builder.AppendLine(dialogBox.DialogTemplate.MenuResourceOrdinal, $"{padding}Menu resource ordinal"); builder.AppendLine(dialogBox.DialogTemplate.ClassResource, $"{padding}Class resource"); builder.AppendLine(dialogBox.DialogTemplate.ClassResourceOrdinal, $"{padding}Class resource ordinal"); builder.AppendLine(dialogBox.DialogTemplate.TitleResource, $"{padding}Title resource"); builder.AppendLine(dialogBox.DialogTemplate.PointSizeValue, $"{padding}Point size value"); builder.AppendLine(dialogBox.DialogTemplate.Typeface, $"{padding}Typeface"); builder.AppendLine(); builder.AppendLine($"{padding}Dialog item templates"); builder.AppendLine($"{padding}-------------------------"); if (dialogBox.DialogTemplate.ItemCount == 0 || dialogBox.DialogItemTemplates is null || dialogBox.DialogItemTemplates.Length == 0) { builder.AppendLine($"{padding}No dialog item templates"); return; } for (int i = 0; i < dialogBox.DialogItemTemplates.Length; i++) { var dialogItemTemplate = dialogBox.DialogItemTemplates[i]; builder.AppendLine($"{padding}Dialog item template {i}"); if (dialogItemTemplate is null) { builder.AppendLine($"{padding} [NULL]"); continue; } builder.AppendLine($"{padding} Style: {dialogItemTemplate.Style} (0x{dialogItemTemplate.Style:X})"); builder.AppendLine($"{padding} Extended style: {dialogItemTemplate.ExtendedStyle} (0x{dialogItemTemplate.ExtendedStyle:X})"); builder.AppendLine(dialogItemTemplate.PositionX, $"{padding} X-coordinate of upper-left corner"); builder.AppendLine(dialogItemTemplate.PositionY, $"{padding} Y-coordinate of upper-left corner"); builder.AppendLine(dialogItemTemplate.WidthX, $"{padding} Width of the control"); builder.AppendLine(dialogItemTemplate.HeightY, $"{padding} Height of the control"); builder.AppendLine(dialogItemTemplate.ID, $"{padding} ID"); builder.AppendLine(dialogItemTemplate.ClassResource, $"{padding} Class resource"); builder.AppendLine($"{padding} Class resource ordinal: {dialogItemTemplate.ClassResourceOrdinal} (0x{dialogItemTemplate.ClassResourceOrdinal:X})"); builder.AppendLine(dialogItemTemplate.TitleResource, $"{padding} Title resource"); builder.AppendLine(dialogItemTemplate.TitleResourceOrdinal, $"{padding} Title resource ordinal"); builder.AppendLine(dialogItemTemplate.CreationDataSize, $"{padding} Creation data size"); if (dialogItemTemplate.CreationData is not null && dialogItemTemplate.CreationData.Length != 0) builder.AppendLine(dialogItemTemplate.CreationData, $"{padding} Creation data"); else builder.AppendLine($"{padding} Creation data: [EMPTY]"); } } else if (dialogBox.ExtendedDialogTemplate is not null) { builder.AppendLine(dialogBox.ExtendedDialogTemplate.Version, $"{padding}Version"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.Signature, $"{padding}Signature"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.HelpID, $"{padding}Help ID"); 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(dialogBox.ExtendedDialogTemplate.DialogItems, $"{padding}Item count"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.PositionX, $"{padding}X-coordinate of upper-left corner"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.PositionY, $"{padding}Y-coordinate of upper-left corner"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.WidthX, $"{padding}Width of the dialog box"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.HeightY, $"{padding}Height of the dialog box"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.MenuResource, $"{padding}Menu resource"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.MenuResourceOrdinal, $"{padding}Menu resource ordinal"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.ClassResource, $"{padding}Class resource"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.ClassResourceOrdinal, $"{padding}Class resource ordinal"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.TitleResource, $"{padding}Title resource"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.PointSize, $"{padding}Point size"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.Weight, $"{padding}Weight"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.Italic, $"{padding}Italic"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.CharSet, $"{padding}Character set"); builder.AppendLine(dialogBox.ExtendedDialogTemplate.Typeface, $"{padding}Typeface"); builder.AppendLine(); builder.AppendLine($"{padding}Dialog item templates"); builder.AppendLine($"{padding}-------------------------"); if (dialogBox.ExtendedDialogTemplate.DialogItems == 0 || dialogBox.ExtendedDialogItemTemplates is null || dialogBox.ExtendedDialogItemTemplates.Length == 0) { builder.AppendLine($"{padding}No dialog item templates"); return; } for (int i = 0; i < dialogBox.ExtendedDialogItemTemplates.Length; i++) { var dialogItemTemplate = dialogBox.ExtendedDialogItemTemplates[i]; builder.AppendLine($"{padding}Dialog item template {i}"); if (dialogItemTemplate is null) { builder.AppendLine($"{padding} [NULL]"); continue; } builder.AppendLine(dialogItemTemplate.HelpID, $"{padding} Help ID"); builder.AppendLine($"{padding} Extended style: {dialogItemTemplate.ExtendedStyle} (0x{dialogItemTemplate.ExtendedStyle:X})"); builder.AppendLine($"{padding} Style: {dialogItemTemplate.Style} (0x{dialogItemTemplate.Style:X})"); builder.AppendLine(dialogItemTemplate.PositionX, $"{padding} X-coordinate of upper-left corner"); builder.AppendLine(dialogItemTemplate.PositionY, $"{padding} Y-coordinate of upper-left corner"); builder.AppendLine(dialogItemTemplate.WidthX, $"{padding} Width of the control"); builder.AppendLine(dialogItemTemplate.HeightY, $"{padding} Height of the control"); builder.AppendLine(dialogItemTemplate.ID, $"{padding} ID"); builder.AppendLine(dialogItemTemplate.ClassResource, $"{padding} Class resource"); builder.AppendLine($"{padding} Class resource ordinal: {dialogItemTemplate.ClassResourceOrdinal} (0x{dialogItemTemplate.ClassResourceOrdinal:X})"); builder.AppendLine(dialogItemTemplate.TitleResource, $"{padding} Title resource"); builder.AppendLine(dialogItemTemplate.TitleResourceOrdinal, $"{padding} Title resource ordinal"); builder.AppendLine(dialogItemTemplate.CreationDataSize, $"{padding} Creation data size"); if (dialogItemTemplate.CreationData is not null && dialogItemTemplate.CreationData.Length != 0) builder.AppendLine(dialogItemTemplate.CreationData, $"{padding} Creation data"); else builder.AppendLine($"{padding} Creation data: [EMPTY]"); } } else { builder.AppendLine($"{padding}Dialog box resource found, but malformed"); } } private static void PrintResourceRT_STRING(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); StringTableResource? stringTable = null; try { stringTable = Serialization.Readers.PortableExecutable.ParseStringTableResource(entry.Data); } catch { } if (stringTable is null) { builder.AppendLine($"{padding}String table resource found, but malformed"); return; } foreach (var kvp in stringTable.Data) { int index = kvp.Key; string? stringValue = kvp.Value; builder.AppendLine(stringValue, $"{padding}String entry {index}"); } } private static void PrintResourceRT_FONTDIR(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Font directory resource found, not parsed yet"); } private static void PrintResourceRT_FONT(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Font resource found, not parsed yet"); } private static void PrintResourceRT_ACCELERATOR(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); AcceleratorTable? acceleratorTable = null; try { acceleratorTable = Serialization.Readers.PortableExecutable.ParseAcceleratorTable(entry.Data); } catch { } if (acceleratorTable?.Entries is null) { builder.AppendLine($"{padding}Accelerator table resource found, but malformed"); return; } for (int i = 0; i < acceleratorTable.Entries.Length; i++) { var acceleratorTableEntry = acceleratorTable.Entries[i]; builder.AppendLine($"{padding}Accelerator Table Entry {i}:"); builder.AppendLine($"{padding} Flags: {acceleratorTableEntry.Flags} (0x{acceleratorTableEntry.Flags:X})"); builder.AppendLine(acceleratorTableEntry.Ansi, $"{padding} Ansi"); builder.AppendLine(acceleratorTableEntry.Id, $"{padding} Id"); builder.AppendLine(acceleratorTableEntry.Padding, $"{padding} Padding"); } } private static void PrintResourceRT_RCDATA(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Application-defined resource found, not parsed yet"); // Then print the data, if needed if (entry.Data is null) { builder.AppendLine($"{padding}Data: [NULL] (This may indicate a very large resource)"); } else { int offset = 0; byte[] magic = entry.Data.ReadBytes(ref offset, Math.Min(entry.Data.Length, 16)); if (magic.StartsWith([0x4D, 0x5A])) { builder.AppendLine($"{padding}Data: [Embedded Executable File]"); // TODO: Parse this out and print separately } else if (magic.StartsWith([0x4D, 0x53, 0x46, 0x54])) { builder.AppendLine($"{padding}Data: [Embedded OLE Library File]"); // TODO: Parse this out and print separately } else if (magic.StartsWith([0x50, 0x4B, 0x03, 0x04])) { builder.AppendLine($"{padding}Data: [Embedded PKZIP file]"); // TODO: Parse this out and print separately } else if (magic.StartsWith([0x50, 0x4B, 0x05, 0x06])) { builder.AppendLine($"{padding}Data: [Embedded empty PKZIP file]"); // TODO: Parse this out and print separately } else if (magic.StartsWith([0x50, 0x4B, 0x07, 0x08])) { builder.AppendLine($"{padding}Data: [Embedded spanned PKZIP file]"); // TODO: Parse this out and print separately } else if (magic.StartsWith(Data.Models.RAR.Constants.OldSignatureBytes)) { builder.AppendLine($"{padding}Data: [Embedded RAR file]"); // TODO: Parse this out and print separately } else if (magic.StartsWith(Data.Models.RAR.Constants.NewSignatureBytes)) { builder.AppendLine($"{padding}Data: [Embedded RAR5 file]"); // TODO: Parse this out and print separately } else { builder.AppendLine(magic, $"{padding}Data"); //if (entry.Data is not null) // builder.AppendLine(entry.Data, $"{padding}Value (Byte Data)"); //if (entry.Data is not null) // builder.AppendLine(Encoding.ASCII.GetString(entry.Data), $"{padding}Value (ASCII)"); //if (entry.Data is not null) // builder.AppendLine(Encoding.UTF8.GetString(entry.Data), $"{padding}Value (UTF-8)"); //if (entry.Data is not null) // builder.AppendLine(Encoding.Unicode.GetString(entry.Data), $"{padding}Value (Unicode)"); } } } private static void PrintResourceRT_MESSAGETABLE(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); MessageResourceData? messageTable = null; try { messageTable = Serialization.Readers.PortableExecutable.ParseMessageResourceData(entry.Data); } catch { } if (messageTable is null) { builder.AppendLine($"{padding}Message resource data found, but malformed"); return; } builder.AppendLine(messageTable.NumberOfBlocks, $"{padding}Number of blocks"); builder.AppendLine(); builder.AppendLine($"{padding}Message resource blocks"); builder.AppendLine($"{padding}-------------------------"); if (messageTable.NumberOfBlocks == 0 || messageTable.Blocks.Length == 0) { builder.AppendLine($"{padding}No message resource blocks"); } else { for (int i = 0; i < messageTable.Blocks.Length; i++) { var messageResourceBlock = messageTable.Blocks[i]; builder.AppendLine($"{padding}Message resource block {i}"); if (messageResourceBlock is null) { builder.AppendLine($"{padding} [NULL]"); continue; } builder.AppendLine(messageResourceBlock.LowId, $"{padding} Low ID"); builder.AppendLine(messageResourceBlock.HighId, $"{padding} High ID"); builder.AppendLine(messageResourceBlock.OffsetToEntries, $"{padding} Offset to entries"); } } builder.AppendLine(); builder.AppendLine($"{padding}Message resource entries"); builder.AppendLine($"{padding}-------------------------"); if (messageTable.Entries.Count == 0) { builder.AppendLine($"{padding}No message resource entries"); } else { foreach (var kvp in messageTable.Entries) { uint index = kvp.Key; var messageResourceEntry = kvp.Value; builder.AppendLine($"{padding}Message resource entry {index}"); if (messageResourceEntry is null) { builder.AppendLine($"{padding} [NULL]"); continue; } builder.AppendLine(messageResourceEntry.Length, $"{padding} Length"); builder.AppendLine(messageResourceEntry.Flags, $"{padding} Flags"); builder.AppendLine(messageResourceEntry.Text, $"{padding} Text"); } } } private static void PrintResourceRT_GROUP_CURSOR(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Hardware-independent cursor resource found, not parsed yet"); } private static void PrintResourceRT_GROUP_ICON(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Hardware-independent icon resource found, not parsed yet"); } private static void PrintResourceRT_VERSION(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); VersionInfo? versionInfo = null; try { versionInfo = Serialization.Readers.PortableExecutable.ParseVersionInfo(entry.Data); } catch { } if (versionInfo is null) { builder.AppendLine($"{padding}Version info resource found, but malformed"); return; } builder.AppendLine(versionInfo.Length, $"{padding}Length"); builder.AppendLine(versionInfo.ValueLength, $"{padding}Value length"); builder.AppendLine($"{padding}Resource type: {versionInfo.ResourceType} (0x{versionInfo.ResourceType:X})"); builder.AppendLine(versionInfo.Key, $"{padding}Key"); if (versionInfo.ValueLength != 0 && versionInfo.Value is not null) { builder.AppendLine(versionInfo.Value.Signature, $"{padding}[Fixed File Info] Signature"); builder.AppendLine(versionInfo.Value.StrucVersion, $"{padding}[Fixed File Info] Struct version"); builder.AppendLine(versionInfo.Value.FileVersionMS, $"{padding}[Fixed File Info] File version (MS)"); builder.AppendLine(versionInfo.Value.FileVersionLS, $"{padding}[Fixed File Info] File version (LS)"); builder.AppendLine(versionInfo.Value.ProductVersionMS, $"{padding}[Fixed File Info] Product version (MS)"); builder.AppendLine(versionInfo.Value.ProductVersionLS, $"{padding}[Fixed File Info] Product version (LS)"); builder.AppendLine(versionInfo.Value.FileFlagsMask, $"{padding}[Fixed File Info] File flags mask"); 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(versionInfo.Value.FileDateMS, $"{padding}[Fixed File Info] File date (MS)"); builder.AppendLine(versionInfo.Value.FileDateLS, $"{padding}[Fixed File Info] File date (LS)"); } if (versionInfo.StringFileInfo is not null) { builder.AppendLine(versionInfo.StringFileInfo.Length, $"{padding}[String File Info] Length"); builder.AppendLine(versionInfo.StringFileInfo.ValueLength, $"{padding}[String File Info] Value length"); builder.AppendLine($"{padding}[String File Info] Resource type: {versionInfo.StringFileInfo.ResourceType} (0x{versionInfo.StringFileInfo.ResourceType:X})"); builder.AppendLine(versionInfo.StringFileInfo.Key, $"{padding}[String File Info] Key"); builder.AppendLine($"{padding}Children:"); builder.AppendLine($"{padding}-------------------------"); if (versionInfo.StringFileInfo.Children.Length == 0) { builder.AppendLine($"{padding}No string file info children"); } else { for (int i = 0; i < versionInfo.StringFileInfo.Children.Length; i++) { var stringFileInfoChildEntry = versionInfo.StringFileInfo.Children[i]; if (stringFileInfoChildEntry is null) { builder.AppendLine($"{padding} [String Table {i}] [NULL]"); continue; } builder.AppendLine(stringFileInfoChildEntry.Length, $"{padding} [String Table {i}] Length"); builder.AppendLine(stringFileInfoChildEntry.ValueLength, $"{padding} [String Table {i}] Value length"); builder.AppendLine($"{padding} [String Table {i}] ResourceType: {stringFileInfoChildEntry.ResourceType} (0x{stringFileInfoChildEntry.ResourceType:X})"); builder.AppendLine(stringFileInfoChildEntry.Key, $"{padding} [String Table {i}] Key"); builder.AppendLine($"{padding} [String Table {i}] Children:"); builder.AppendLine($"{padding} -------------------------"); if (stringFileInfoChildEntry.Children.Length == 0) { builder.AppendLine($"{padding} No string table {i} children"); } else { for (int j = 0; j < stringFileInfoChildEntry.Children.Length; j++) { var stringDataEntry = stringFileInfoChildEntry.Children[j]; if (stringDataEntry is null) { builder.AppendLine($"{padding} [String Data {j}] [NULL]"); continue; } builder.AppendLine(stringDataEntry.Length, $"{padding} [String Data {j}] Length"); builder.AppendLine(stringDataEntry.ValueLength, $"{padding} [String Data {j}] Value length"); builder.AppendLine($"{padding} [String Data {j}] ResourceType: {stringDataEntry.ResourceType} (0x{stringDataEntry.ResourceType:X})"); builder.AppendLine(stringDataEntry.Key, $"{padding} [String Data {j}] Key"); builder.AppendLine(stringDataEntry.Value, $"{padding} [String Data {j}] Value"); } } } } } if (versionInfo.VarFileInfo is not null) { builder.AppendLine(versionInfo.VarFileInfo.Length, $"{padding}[Var File Info] Length"); builder.AppendLine(versionInfo.VarFileInfo.ValueLength, $"{padding}[Var File Info] Value length"); builder.AppendLine($"{padding}[Var File Info] Resource type: {versionInfo.VarFileInfo.ResourceType} (0x{versionInfo.VarFileInfo.ResourceType:X})"); builder.AppendLine(versionInfo.VarFileInfo.Key, $"{padding}[Var File Info] Key"); builder.AppendLine($"{padding}Children:"); builder.AppendLine($"{padding}-------------------------"); if (versionInfo.VarFileInfo.Children.Length == 0) { builder.AppendLine($"{padding}No var file info children"); } else { for (int i = 0; i < versionInfo.VarFileInfo.Children.Length; i++) { var varFileInfoChildEntry = versionInfo.VarFileInfo.Children[i]; if (varFileInfoChildEntry is null) { builder.AppendLine($"{padding} [String Table {i}] [NULL]"); continue; } builder.AppendLine(varFileInfoChildEntry.Length, $"{padding} [String Table {i}] Length"); builder.AppendLine(varFileInfoChildEntry.ValueLength, $"{padding} [String Table {i}] Value length"); builder.AppendLine($"{padding} [String Table {i}] ResourceType: {varFileInfoChildEntry.ResourceType} (0x{varFileInfoChildEntry.ResourceType:X})"); builder.AppendLine(varFileInfoChildEntry.Key, $"{padding} [String Table {i}] Key"); builder.AppendLine(varFileInfoChildEntry.Value, $"{padding} [String Table {i}] Value"); } } } } private static void PrintResourceRT_DLGINCLUDE(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}External header resource found, not parsed yet"); } private static void PrintResourceRT_PLUGPLAY(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Plug and Play resource found, not parsed yet"); } private static void PrintResourceRT_VXD(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}VXD found, not parsed yet"); } private static void PrintResourceRT_ANICURSOR(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Animated cursor found, not parsed yet"); } private static void PrintResourceRT_ANIICON(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}Animated icon found, not parsed yet"); } private static void PrintResourceRT_HTML(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); builder.AppendLine($"{padding}HTML resource found, not parsed yet"); //if (entry.Data is not null) // builder.AppendLine(Encoding.ASCII.GetString(entry.Data), $"{padding}Value (ASCII)"); //if (entry.Data is not null) // builder.AppendLine(Encoding.UTF8.GetString(entry.Data), $"{padding}Value (UTF-8)"); //if (entry.Data is not null) // builder.AppendLine(Encoding.Unicode.GetString(entry.Data), $"{padding}Value (Unicode)"); } private static void PrintResourceRT_MANIFEST(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); AssemblyManifest? assemblyManifest = null; try { assemblyManifest = Serialization.Readers.PortableExecutable.ParseAssemblyManifest(entry.Data); } catch { } if (assemblyManifest is null) { builder.AppendLine($"{padding}Assembly manifest found, but malformed"); return; } builder.AppendLine(assemblyManifest.ManifestVersion, $"{padding}Manifest version"); if (assemblyManifest.AssemblyIdentities is not null && assemblyManifest.AssemblyIdentities.Length > 0) { for (int i = 0; i < assemblyManifest.AssemblyIdentities.Length; i++) { var assemblyIdentity = assemblyManifest.AssemblyIdentities[i]; builder.AppendLine(assemblyIdentity.Name, $"{padding}[Assembly Identity {i}] Name"); builder.AppendLine(assemblyIdentity.Version, $"{padding}[Assembly Identity {i}] Version"); builder.AppendLine(assemblyIdentity.Type, $"{padding}[Assembly Identity {i}] Type"); builder.AppendLine(assemblyIdentity.ProcessorArchitecture, $"{padding}[Assembly Identity {i}] Processor architecture"); builder.AppendLine(assemblyIdentity.PublicKeyToken, $"{padding}[Assembly Identity {i}] Public key token"); builder.AppendLine(assemblyIdentity.Language, $"{padding}[Assembly Identity {i}] Language"); } } if (assemblyManifest.Description is not null) builder.AppendLine(assemblyManifest.Description.Value, $"{padding}[Assembly Description] Value"); if (assemblyManifest.COMInterfaceExternalProxyStub is not null && assemblyManifest.COMInterfaceExternalProxyStub.Length > 0) { for (int i = 0; i < assemblyManifest.COMInterfaceExternalProxyStub.Length; i++) { var comInterfaceExternalProxyStub = assemblyManifest.COMInterfaceExternalProxyStub[i]; builder.AppendLine(comInterfaceExternalProxyStub.IID, $"{padding}[COM Interface External Proxy Stub {i}] IID"); builder.AppendLine(comInterfaceExternalProxyStub.Name, $"{padding}[COM Interface External Proxy Stub {i}] Name"); builder.AppendLine(comInterfaceExternalProxyStub.TLBID, $"{padding}[COM Interface External Proxy Stub {i}] TLBID"); builder.AppendLine(comInterfaceExternalProxyStub.NumMethods, $"{padding}[COM Interface External Proxy Stub {i}] Number of methods"); builder.AppendLine(comInterfaceExternalProxyStub.ProxyStubClsid32, $"{padding}[COM Interface External Proxy Stub {i}] Proxy stub (CLSID32)"); builder.AppendLine(comInterfaceExternalProxyStub.BaseInterface, $"{padding}[COM Interface External Proxy Stub {i}] Base interface"); } } if (assemblyManifest.Dependency is not null && assemblyManifest.Dependency.Length > 0) { for (int i = 0; i < assemblyManifest.Dependency.Length; i++) { var dependency = assemblyManifest.Dependency[i]; if (dependency?.DependentAssembly is not null) { if (dependency.DependentAssembly.AssemblyIdentity is not null) { builder.AppendLine(dependency.DependentAssembly.AssemblyIdentity.Name, $"{padding}[Dependency {i} Assembly Identity] Name"); builder.AppendLine(dependency.DependentAssembly.AssemblyIdentity.Version, $"{padding}[Dependency {i} Assembly Identity] Version"); builder.AppendLine(dependency.DependentAssembly.AssemblyIdentity.Type, $"{padding}[Dependency {i} Assembly Identity] Type"); builder.AppendLine(dependency.DependentAssembly.AssemblyIdentity.ProcessorArchitecture, $"{padding}[Dependency {i} Assembly Identity] Processor architecture"); builder.AppendLine(dependency.DependentAssembly.AssemblyIdentity.PublicKeyToken, $"{padding}[Dependency {i} Assembly Identity] Public key token"); builder.AppendLine(dependency.DependentAssembly.AssemblyIdentity.Language, $"{padding}[Dependency {i} Assembly Identity] Language"); } if (dependency.DependentAssembly.BindingRedirect is not null && dependency.DependentAssembly.BindingRedirect.Length > 0) { for (int j = 0; j < dependency.DependentAssembly.BindingRedirect.Length; j++) { var bindingRedirect = dependency.DependentAssembly.BindingRedirect[j]; builder.AppendLine(bindingRedirect.OldVersion, $"{padding}[Dependency {i} Binding Redirect {j}] Old version"); builder.AppendLine(bindingRedirect.NewVersion, $"{padding}[Dependency {i} Binding Redirect {j}] New version"); } } } if (dependency is not null) builder.AppendLine(dependency.Optional, $"{padding}[Dependency {i}] Optional"); } } if (assemblyManifest.File is not null && assemblyManifest.File.Length > 0) { for (int i = 0; i < assemblyManifest.File.Length; i++) { var file = assemblyManifest.File[i]; if (file is null) { builder.AppendLine($"{padding}[File {i}] [NULL]"); continue; } builder.AppendLine(file.Name, $"{padding}[File {i}] Name"); builder.AppendLine(file.Hash, $"{padding}[File {i}] Hash"); builder.AppendLine(file.HashAlgorithm, $"{padding}[File {i}] Hash algorithm"); builder.AppendLine(file.Size, $"{padding}[File {i}] Size"); if (file.COMClass is not null && file.COMClass.Length > 0) { for (int j = 0; j < file.COMClass.Length; j++) { var comClass = file.COMClass[j]; builder.AppendLine(comClass.CLSID, $"{padding}[File {i} COM Class {j}] CLSID"); builder.AppendLine(comClass.ThreadingModel, $"{padding}[File {i} COM Class {j}] Threading model"); builder.AppendLine(comClass.ProgID, $"{padding}[File {i} COM Class {j}] Prog ID"); builder.AppendLine(comClass.TLBID, $"{padding}[File {i} COM Class {j}] TLBID"); builder.AppendLine(comClass.Description, $"{padding}[File {i} COM Class {j}] Description"); if (comClass.ProgIDs is not null && comClass.ProgIDs.Length > 0) { for (int k = 0; k < comClass.ProgIDs.Length; k++) { var progId = comClass.ProgIDs[k]; builder.AppendLine(progId.Value, $"{padding}[File {i} COM Class {j} Prog ID {k}] Value"); } } } } if (file.COMInterfaceProxyStub is not null && file.COMInterfaceProxyStub.Length > 0) { for (int j = 0; j < file.COMInterfaceProxyStub.Length; j++) { var comInterfaceProxyStub = file.COMInterfaceProxyStub[j]; builder.AppendLine(comInterfaceProxyStub.IID, $"{padding}[File {i} COM Interface Proxy Stub {j}] IID"); builder.AppendLine(comInterfaceProxyStub.Name, $"{padding}[File {i} COM Interface Proxy Stub {j}] Name"); builder.AppendLine(comInterfaceProxyStub.TLBID, $"{padding}[File {i} COM Interface Proxy Stub {j}] TLBID"); builder.AppendLine(comInterfaceProxyStub.NumMethods, $"{padding}[File {i} COM Interface Proxy Stub {j}] Number of methods"); builder.AppendLine(comInterfaceProxyStub.ProxyStubClsid32, $"{padding}[File {i} COM Interface Proxy Stub {j}] Proxy stub (CLSID32)"); builder.AppendLine(comInterfaceProxyStub.BaseInterface, $"{padding}[File {i} COM Interface Proxy Stub {j}] Base interface"); } } if (file.Typelib is not null && file.Typelib.Length > 0) { for (int j = 0; j < file.Typelib.Length; j++) { var typeLib = file.Typelib[j]; builder.AppendLine(typeLib.TLBID, $"{padding}[File {i} Type Lib {j}] TLBID"); builder.AppendLine(typeLib.Version, $"{padding}[File {i} Type Lib {j}] Version"); builder.AppendLine(typeLib.HelpDir, $"{padding}[File {i} Type Lib {j}] Help directory"); builder.AppendLine(typeLib.ResourceID, $"{padding}[File {i} Type Lib {j}] Resource ID"); builder.AppendLine(typeLib.Flags, $"{padding}[File {i} Type Lib {j}] Flags"); } } if (file.WindowClass is not null && file.WindowClass.Length > 0) { for (int j = 0; j < file.WindowClass.Length; j++) { var windowClass = file.WindowClass[j]; builder.AppendLine(windowClass.Versioned, $"{padding}[File {i} Window Class {j}] Versioned"); builder.AppendLine(windowClass.Value, $"{padding}[File {i} Window Class {j}] Value"); } } } } if (assemblyManifest.EverythingElse is not null && assemblyManifest.EverythingElse.Length > 0) { for (int i = 0; i < assemblyManifest.EverythingElse.Length; i++) { var thing = assemblyManifest.EverythingElse[i]; if (thing is XmlElement element) { builder.AppendLine(element.OuterXml, $"{padding}Unparsed XML Element {i}"); } else { builder.AppendLine($"{padding}Unparsed Item {i}: {thing ?? "[NULL]"}"); } } } } private static void PrintResourceUNKNOWN(Data.Models.PortableExecutable.Resource.DataEntry entry, int level, object resourceType, StringBuilder builder) { string padding = new(' ', (level + 1) * 2); // Print the type first if (resourceType is uint numericType) builder.AppendLine($"{padding}Type {(ResourceType)numericType} found, not parsed yet"); else if (resourceType is string stringType) builder.AppendLine($"{padding}Type {stringType} found, not parsed yet"); else builder.AppendLine($"{padding}Unknown type {resourceType} found, not parsed yet"); // Then print the data, if needed if (entry.Data is null) { builder.AppendLine($"{padding}Data: [NULL] (This may indicate a very large resource)"); } else { int offset = 0; byte[] magic = entry.Data.ReadBytes(ref offset, Math.Min(entry.Data.Length, 16)); if (magic.StartsWith([0x4D, 0x5A])) { builder.AppendLine($"{padding}Data: [Embedded Executable File]"); // TODO: Parse this out and print separately } else if (magic.StartsWith([0x4D, 0x53, 0x46, 0x54])) { builder.AppendLine($"{padding}Data: [Embedded OLE Library File]"); // TODO: Parse this out and print separately } else if (magic.StartsWith([0x50, 0x4B, 0x03, 0x04])) { builder.AppendLine($"{padding}Data: [Embedded PKZIP file]"); // TODO: Parse this out and print separately } else if (magic.StartsWith([0x50, 0x4B, 0x05, 0x06])) { builder.AppendLine($"{padding}Data: [Embedded empty PKZIP file]"); // TODO: Parse this out and print separately } else if (magic.StartsWith([0x50, 0x4B, 0x07, 0x08])) { builder.AppendLine($"{padding}Data: [Embedded spanned PKZIP file]"); // TODO: Parse this out and print separately } else if (magic.StartsWith(Data.Models.RAR.Constants.OldSignatureBytes)) { builder.AppendLine($"{padding}Data: [Embedded RAR file]"); // TODO: Parse this out and print separately } else if (magic.StartsWith(Data.Models.RAR.Constants.NewSignatureBytes)) { builder.AppendLine($"{padding}Data: [Embedded RAR5 file]"); // TODO: Parse this out and print separately } else { builder.AppendLine(magic, $"{padding}Data"); //if (entry.Data is not null) // builder.AppendLine(entry.Data, $"{padding}Value (Byte Data)"); //if (entry.Data is not null) // builder.AppendLine(Encoding.ASCII.GetString(entry.Data), $"{padding}Value (ASCII)"); //if (entry.Data is not null) // builder.AppendLine(Encoding.UTF8.GetString(entry.Data), $"{padding}Value (UTF-8)"); //if (entry.Data is not null) // builder.AppendLine(Encoding.Unicode.GetString(entry.Data), $"{padding}Value (Unicode)"); } } } } }