mirror of
https://github.com/SabreTools/SabreTools.Serialization.git
synced 2026-04-05 22:01:33 +00:00
1892 lines
99 KiB
C#
1892 lines
99 KiB
C#
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
|
|
/// <inheritdoc/>
|
|
public string ExportJSON() => System.Text.Json.JsonSerializer.Serialize(Model, _jsonSerializerOptions);
|
|
#endif
|
|
|
|
/// <inheritdoc/>
|
|
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<int, Data.Models.PortableExecutable.Import.LookupTableEntry[]?>? 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<int, Data.Models.PortableExecutable.Import.AddressTableEntry[]?>? 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<object> 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<object>(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<object> 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<object> 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)");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|