mirror of https://github.com/icsharpcode/ILSpy.git
Browse Source
Adds the five PE-format leaves (DOS / COFF / Optional / DataDirectories / DebugDirectory) under each assembly's Metadata folder. Phase 1 renders them as fixed-width text tables via Decompile; Phase 2 will swap to a DataGrid tab. Introduces Entry / BitEntry / ColumnInfoAttribute and a MetadataTextWriter helper that the heap and table nodes reuse. Assisted-by: Claude:claude-opus-4-7:Claude Codepull/3755/head
9 changed files with 848 additions and 3 deletions
@ -0,0 +1,127 @@
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
|
||||
using Avalonia.Headless.NUnit; |
||||
|
||||
using AwesomeAssertions; |
||||
|
||||
using ILSpy.AppEnv; |
||||
using ILSpy.Metadata; |
||||
using ILSpy.TreeNodes; |
||||
using ILSpy.ViewModels; |
||||
using ILSpy.Views; |
||||
|
||||
using NUnit.Framework; |
||||
|
||||
namespace ICSharpCode.ILSpy.Tests.Metadata; |
||||
|
||||
[TestFixture] |
||||
public class PEHeaderTreeTests |
||||
{ |
||||
[AvaloniaTest] |
||||
public async Task MetadataTreeNode_Surfaces_Five_PE_Header_Children_For_A_PE_Assembly() |
||||
{ |
||||
// The Metadata folder under a PE assembly should expose five PE-format leaves:
|
||||
// DOS / COFF / Optional / DataDirectories / DebugDirectory. Order mirrors WPF so a
|
||||
// user shifting between hosts sees the same tree shape. Each node is the entry point
|
||||
// to a header / table view; Phase 1 renders text, Phase 2 swaps to a DataGrid.
|
||||
|
||||
var window = AppComposition.Current.GetExport<MainWindow>(); |
||||
window.Show(); |
||||
var vm = (MainWindowViewModel)window.DataContext!; |
||||
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1); |
||||
|
||||
var coreLibName = typeof(object).Assembly.GetName().Name!; |
||||
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>(coreLibName); |
||||
assemblyNode.EnsureLazyChildren(); |
||||
var metadataNode = assemblyNode.Children.OfType<MetadataTreeNode>().Single(); |
||||
metadataNode.EnsureLazyChildren(); |
||||
|
||||
metadataNode.Children.OfType<DosHeaderTreeNode>().Should().ContainSingle(); |
||||
metadataNode.Children.OfType<CoffHeaderTreeNode>().Should().ContainSingle(); |
||||
metadataNode.Children.OfType<OptionalHeaderTreeNode>().Should().ContainSingle(); |
||||
metadataNode.Children.OfType<DataDirectoriesTreeNode>().Should().ContainSingle(); |
||||
metadataNode.Children.OfType<DebugDirectoryTreeNode>().Should().ContainSingle(); |
||||
|
||||
var orderedTypes = metadataNode.Children.Take(5).Select(c => c.GetType()).ToList(); |
||||
orderedTypes.Should().Equal( |
||||
typeof(DosHeaderTreeNode), |
||||
typeof(CoffHeaderTreeNode), |
||||
typeof(OptionalHeaderTreeNode), |
||||
typeof(DataDirectoriesTreeNode), |
||||
typeof(DebugDirectoryTreeNode)); |
||||
} |
||||
|
||||
[AvaloniaTest] |
||||
public async Task DosHeaderTreeNode_Decompiles_To_A_Table_With_All_31_DOS_Header_Fields() |
||||
{ |
||||
// DOS header is a fixed 64-byte block at offset 0; the 31 fields are well-known and
|
||||
// stable across every PE file. Selecting the node should produce a text table that
|
||||
// every reader can scan, with the magic-number row visible by both its raw value and
|
||||
// its semantic meaning.
|
||||
|
||||
var window = AppComposition.Current.GetExport<MainWindow>(); |
||||
window.Show(); |
||||
var vm = (MainWindowViewModel)window.DataContext!; |
||||
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1); |
||||
|
||||
var coreLibName = typeof(object).Assembly.GetName().Name!; |
||||
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>(coreLibName); |
||||
assemblyNode.EnsureLazyChildren(); |
||||
var metadataNode = assemblyNode.Children.OfType<MetadataTreeNode>().Single(); |
||||
metadataNode.EnsureLazyChildren(); |
||||
var dosNode = metadataNode.Children.OfType<DosHeaderTreeNode>().Single(); |
||||
|
||||
vm.AssemblyTreeModel.SelectNode(dosNode); |
||||
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync(); |
||||
|
||||
tab.Text.Should().Contain("e_magic"); |
||||
tab.Text.Should().Contain("Magic Number (MZ)"); |
||||
tab.Text.Should().Contain("e_lfanew"); |
||||
tab.Text.Should().Contain("File address of new exe header"); |
||||
// All 31 DOS-header field rows should be present — count e_ prefixes on member rows.
|
||||
var fieldCount = System.Text.RegularExpressions.Regex.Matches(tab.Text, @"\be_[a-z0-9_\[\]]+").Count; |
||||
fieldCount.Should().BeGreaterThanOrEqualTo(31); |
||||
} |
||||
|
||||
[AvaloniaTest] |
||||
public async Task CoffHeaderTreeNode_Decompiles_To_A_Table_Including_Machine_And_Characteristics() |
||||
{ |
||||
var window = AppComposition.Current.GetExport<MainWindow>(); |
||||
window.Show(); |
||||
var vm = (MainWindowViewModel)window.DataContext!; |
||||
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 1); |
||||
|
||||
var coreLibName = typeof(object).Assembly.GetName().Name!; |
||||
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>(coreLibName); |
||||
assemblyNode.EnsureLazyChildren(); |
||||
var metadataNode = assemblyNode.Children.OfType<MetadataTreeNode>().Single(); |
||||
metadataNode.EnsureLazyChildren(); |
||||
var coffNode = metadataNode.Children.OfType<CoffHeaderTreeNode>().Single(); |
||||
|
||||
vm.AssemblyTreeModel.SelectNode(coffNode); |
||||
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync(); |
||||
|
||||
tab.Text.Should().Contain("Machine"); |
||||
tab.Text.Should().Contain("Number of Sections"); |
||||
tab.Text.Should().Contain("Characteristics"); |
||||
} |
||||
} |
||||
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
using ILSpy.Languages; |
||||
using ILSpy.TreeNodes; |
||||
|
||||
namespace ILSpy.Metadata |
||||
{ |
||||
/// <summary>
|
||||
/// COFF (Common Object File Format) header — 20 bytes describing target machine, section
|
||||
/// count, link timestamp, and file-level characteristics. The Characteristics field is a
|
||||
/// 16-bit flags word; each individual bit is broken out as a row-detail entry.
|
||||
/// </summary>
|
||||
public sealed class CoffHeaderTreeNode : ILSpyTreeNode |
||||
{ |
||||
readonly PEFile module; |
||||
|
||||
public CoffHeaderTreeNode(PEFile module) |
||||
{ |
||||
this.module = module ?? throw new ArgumentNullException(nameof(module)); |
||||
} |
||||
|
||||
public override object Text => "COFF Header"; |
||||
public override object Icon => Images.Images.MetadataTable; |
||||
public override string ToString() => "COFF Header"; |
||||
|
||||
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) |
||||
{ |
||||
language.WriteCommentLine(output, "COFF Header"); |
||||
MetadataTextWriter.WriteTable(language, output, BuildEntries()); |
||||
} |
||||
|
||||
IReadOnlyList<Entry> BuildEntries() |
||||
{ |
||||
var headers = module.Reader.PEHeaders; |
||||
var header = headers.CoffHeader; |
||||
var linkerDateTime = DateTimeOffset.FromUnixTimeSeconds(unchecked((uint)header.TimeDateStamp)).DateTime; |
||||
int characteristics = (int)header.Characteristics; |
||||
return new List<Entry> { |
||||
new(headers.CoffHeaderStartOffset, (int)header.Machine, 2, "Machine", header.Machine.ToString()), |
||||
new(headers.CoffHeaderStartOffset + 2, (int)header.NumberOfSections, 2, "Number of Sections", "Number of sections; indicates size of the Section Table, which immediately follows the headers."), |
||||
new(headers.CoffHeaderStartOffset + 4, header.TimeDateStamp, 4, "Time/Date Stamp", $"{linkerDateTime} (UTC) / {linkerDateTime.ToLocalTime()} - Time and date the file was created in seconds since January 1st 1970 00:00:00 or 0. Note that for deterministic builds this value is meaningless."), |
||||
new(headers.CoffHeaderStartOffset + 8, header.PointerToSymbolTable, 4, "Pointer to Symbol Table", "Always 0 in .NET executables."), |
||||
new(headers.CoffHeaderStartOffset + 12, header.NumberOfSymbols, 4, "Number of Symbols", "Always 0 in .NET executables."), |
||||
new(headers.CoffHeaderStartOffset + 16, (int)header.SizeOfOptionalHeader, 2, "Optional Header Size", "Size of the optional header."), |
||||
new(headers.CoffHeaderStartOffset + 18, characteristics, 2, "Characteristics", "Flags indicating attributes of the file.", new BitEntry[] { |
||||
new((characteristics & 0x0001) != 0, "<0001> Relocation info stripped from file"), |
||||
new((characteristics & 0x0002) != 0, "<0002> File is executable"), |
||||
new((characteristics & 0x0004) != 0, "<0004> Line numbers stripped from file"), |
||||
new((characteristics & 0x0008) != 0, "<0008> Local symbols stripped from file"), |
||||
new((characteristics & 0x0010) != 0, "<0010> Aggressively trim working set"), |
||||
new((characteristics & 0x0020) != 0, "<0020> Large address aware"), |
||||
new((characteristics & 0x0040) != 0, "<0040> Reserved"), |
||||
new((characteristics & 0x0080) != 0, "<0080> Bytes of machine words are reversed (Low)"), |
||||
new((characteristics & 0x0100) != 0, "<0100> 32-bit word machine"), |
||||
new((characteristics & 0x0200) != 0, "<0200> Debugging info stripped from file in .DBG file"), |
||||
new((characteristics & 0x0400) != 0, "<0400> If image is on removable media, copy and run from the swap file"), |
||||
new((characteristics & 0x0800) != 0, "<0800> If image is on Net, copy and run from the swap file"), |
||||
new((characteristics & 0x1000) != 0, "<1000> System"), |
||||
new((characteristics & 0x2000) != 0, "<2000> DLL"), |
||||
new((characteristics & 0x4000) != 0, "<4000> File should only be run on a UP machine"), |
||||
new((characteristics & 0x8000) != 0, "<8000> Bytes of machine words are reversed (High)"), |
||||
}), |
||||
}; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,97 @@
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Reflection.PortableExecutable; |
||||
|
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
using ILSpy.Languages; |
||||
using ILSpy.TreeNodes; |
||||
|
||||
namespace ILSpy.Metadata |
||||
{ |
||||
/// <summary>
|
||||
/// 15-row table of (RVA, Size, Containing-Section) triples that lives at the tail of the
|
||||
/// PE Optional Header. Each entry points at one well-known PE region (Export Table,
|
||||
/// Import Table, CLI Header, …).
|
||||
/// </summary>
|
||||
public sealed class DataDirectoriesTreeNode : ILSpyTreeNode |
||||
{ |
||||
readonly PEFile module; |
||||
|
||||
public DataDirectoriesTreeNode(PEFile module) |
||||
{ |
||||
this.module = module ?? throw new ArgumentNullException(nameof(module)); |
||||
} |
||||
|
||||
public override object Text => "Data Directories"; |
||||
public override object Icon => Images.Images.MetadataTable; |
||||
public override string ToString() => "Data Directories"; |
||||
|
||||
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) |
||||
{ |
||||
language.WriteCommentLine(output, "Data Directories"); |
||||
MetadataTextWriter.WriteTable(language, output, BuildEntries()); |
||||
} |
||||
|
||||
IReadOnlyList<DataDirectoryEntry> BuildEntries() |
||||
{ |
||||
var headers = module.Reader.PEHeaders; |
||||
var header = headers.PEHeader!; |
||||
return new List<DataDirectoryEntry> { |
||||
new(headers, "Export Table", header.ExportTableDirectory), |
||||
new(headers, "Import Table", header.ImportTableDirectory), |
||||
new(headers, "Resource Table", header.ResourceTableDirectory), |
||||
new(headers, "Exception Table", header.ExceptionTableDirectory), |
||||
new(headers, "Certificate Table", header.CertificateTableDirectory), |
||||
new(headers, "Base Relocation Table", header.BaseRelocationTableDirectory), |
||||
new(headers, "Debug Table", header.DebugTableDirectory), |
||||
new(headers, "Copyright Table", header.CopyrightTableDirectory), |
||||
new(headers, "Global Pointer Table", header.GlobalPointerTableDirectory), |
||||
new(headers, "Thread Local Storage Table", header.ThreadLocalStorageTableDirectory), |
||||
new(headers, "Load Config", header.LoadConfigTableDirectory), |
||||
new(headers, "Bound Import", header.BoundImportTableDirectory), |
||||
new(headers, "Import Address Table", header.ImportAddressTableDirectory), |
||||
new(headers, "Delay Import Descriptor", header.DelayImportTableDirectory), |
||||
new(headers, "CLI Header", header.CorHeaderTableDirectory), |
||||
}; |
||||
} |
||||
|
||||
public sealed class DataDirectoryEntry |
||||
{ |
||||
public string Name { get; } |
||||
[ColumnInfo("X8")] |
||||
public int RVA { get; } |
||||
[ColumnInfo("X8")] |
||||
public int Size { get; } |
||||
public string Section { get; } |
||||
|
||||
public DataDirectoryEntry(PEHeaders headers, string name, DirectoryEntry entry) |
||||
{ |
||||
Name = name; |
||||
RVA = entry.RelativeVirtualAddress; |
||||
Size = entry.Size; |
||||
int sectionIndex = headers.GetContainingSectionIndex(entry.RelativeVirtualAddress); |
||||
Section = sectionIndex >= 0 ? headers.SectionHeaders[sectionIndex].Name : ""; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,94 @@
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Reflection.PortableExecutable; |
||||
|
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
using ILSpy.Languages; |
||||
using ILSpy.TreeNodes; |
||||
|
||||
namespace ILSpy.Metadata |
||||
{ |
||||
/// <summary>
|
||||
/// Lists each entry of the PE debug directory: timestamp, version, type, and the size /
|
||||
/// addresses of the raw debug payload. Phase 1 renders the entries as text; the
|
||||
/// per-entry sub-tree (CodeView, embedded portable PDB, PDB checksum) lands with the
|
||||
/// rest of the metadata-tables work later in Phase 1.
|
||||
/// </summary>
|
||||
public sealed class DebugDirectoryTreeNode : ILSpyTreeNode |
||||
{ |
||||
readonly PEFile module; |
||||
|
||||
public DebugDirectoryTreeNode(PEFile module) |
||||
{ |
||||
this.module = module ?? throw new ArgumentNullException(nameof(module)); |
||||
} |
||||
|
||||
public override object Text => "Debug Directory"; |
||||
public override object Icon => Images.Images.MetadataTable; |
||||
public override string ToString() => "Debug Directory"; |
||||
|
||||
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) |
||||
{ |
||||
language.WriteCommentLine(output, "Debug Directory"); |
||||
MetadataTextWriter.WriteTable(language, output, BuildEntries()); |
||||
} |
||||
|
||||
IReadOnlyList<DebugDirectoryEntryView> BuildEntries() |
||||
{ |
||||
var entries = new List<DebugDirectoryEntryView>(); |
||||
foreach (var entry in module.Reader.ReadDebugDirectory()) |
||||
{ |
||||
int dataOffset = module.Reader.IsLoadedImage ? entry.DataRelativeVirtualAddress : entry.DataPointer; |
||||
var data = module.Reader.GetEntireImage().GetContent(dataOffset, entry.DataSize); |
||||
entries.Add(new DebugDirectoryEntryView(entry, data.ToHexString(data.Length))); |
||||
} |
||||
return entries; |
||||
} |
||||
|
||||
public sealed class DebugDirectoryEntryView |
||||
{ |
||||
public uint Timestamp { get; } |
||||
public ushort MajorVersion { get; } |
||||
public ushort MinorVersion { get; } |
||||
public string Type { get; } |
||||
public int SizeOfRawData { get; } |
||||
[ColumnInfo("X8")] |
||||
public int AddressOfRawData { get; } |
||||
[ColumnInfo("X8")] |
||||
public int PointerToRawData { get; } |
||||
public string RawData { get; } |
||||
|
||||
public DebugDirectoryEntryView(DebugDirectoryEntry entry, string data) |
||||
{ |
||||
Timestamp = entry.Stamp; |
||||
MajorVersion = entry.MajorVersion; |
||||
MinorVersion = entry.MinorVersion; |
||||
Type = entry.Type.ToString(); |
||||
SizeOfRawData = entry.DataSize; |
||||
AddressOfRawData = entry.DataRelativeVirtualAddress; |
||||
PointerToRawData = entry.DataPointer; |
||||
RawData = data; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
using ILSpy.Languages; |
||||
using ILSpy.TreeNodes; |
||||
|
||||
namespace ILSpy.Metadata |
||||
{ |
||||
/// <summary>
|
||||
/// Renders the 64-byte legacy DOS header sitting at offset 0 of every PE file. Phase 1
|
||||
/// emits a fixed-width text table; Phase 2 swaps to a DataGrid tab.
|
||||
/// </summary>
|
||||
public sealed class DosHeaderTreeNode : ILSpyTreeNode |
||||
{ |
||||
readonly PEFile module; |
||||
|
||||
public DosHeaderTreeNode(PEFile module) |
||||
{ |
||||
this.module = module ?? throw new ArgumentNullException(nameof(module)); |
||||
} |
||||
|
||||
public override object Text => "DOS Header"; |
||||
public override object Icon => Images.Images.MetadataTable; |
||||
public override string ToString() => "DOS Header"; |
||||
|
||||
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) |
||||
{ |
||||
language.WriteCommentLine(output, "DOS Header"); |
||||
MetadataTextWriter.WriteTable(language, output, BuildEntries()); |
||||
} |
||||
|
||||
IReadOnlyList<Entry> BuildEntries() |
||||
{ |
||||
var reader = module.Reader.GetEntireImage().GetReader(0, 64); |
||||
var entries = new List<Entry>(31) { |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_magic", "Magic Number (MZ)"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_cblp", "Bytes on last page of file"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_cp", "Pages in file"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_crlc", "Relocations"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_cparhdr", "Size of header in paragraphs"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_minalloc", "Minimum extra paragraphs needed"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_maxalloc", "Maximum extra paragraphs needed"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_ss", "Initial (relative) SS value"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_sp", "Initial SP value"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_csum", "Checksum"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_ip", "Initial IP value"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_cs", "Initial (relative) CS value"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_lfarlc", "File address of relocation table"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_ovno", "Overlay number"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res[0]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res[1]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res[2]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res[3]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_oemid", "OEM identifier (for e_oeminfo)"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_oeminfo", "OEM information; e_oemid specific"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res2[0]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res2[1]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res2[2]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res2[3]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res2[4]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res2[5]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res2[6]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res2[7]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res2[8]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadUInt16(), 2, "e_res2[9]", "Reserved words"), |
||||
new(reader.Offset, reader.ReadInt32(), 4, "e_lfanew", "File address of new exe header"), |
||||
}; |
||||
return entries; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,93 @@
@@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ILSpy.Metadata |
||||
{ |
||||
/// <summary>
|
||||
/// Classifies a column for the DataGrid view (Phase 2+). Heap-offset cells render with a
|
||||
/// hex-padded width and resolve their string content via the relevant heap reader; token
|
||||
/// cells render as a hyperlink that navigates to the target table row. The text path
|
||||
/// (Phase 1) ignores everything except <c>Format</c>.
|
||||
/// </summary>
|
||||
public enum ColumnKind |
||||
{ |
||||
Other, |
||||
HeapOffset, |
||||
Token, |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Annotates a row-shape property with rendering hints. <c>Format</c> is consumed by the
|
||||
/// text writer; <c>Kind</c> and <c>LinkToTable</c> drive the DataGrid column factory in
|
||||
/// Phase 2+ and are inert in Phase 1.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)] |
||||
public sealed class ColumnInfoAttribute : Attribute |
||||
{ |
||||
public string Format { get; } |
||||
public ColumnKind Kind { get; set; } |
||||
public bool LinkToTable { get; set; } |
||||
|
||||
public ColumnInfoAttribute(string format) |
||||
{ |
||||
Format = format; |
||||
} |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// One row in a PE-header / metadata-table dump. <c>Value</c> is rendered hex-formatted
|
||||
/// at <c>Size * 2</c> digits when numeric; <c>RowDetails</c> carries optional flag-bit
|
||||
/// breakdowns that the DataGrid view (Phase 2) uses to populate row details. The text
|
||||
/// path (Phase 1) ignores <c>RowDetails</c>.
|
||||
/// </summary>
|
||||
public sealed class Entry |
||||
{ |
||||
public string Member { get; } |
||||
public int Offset { get; } |
||||
public int Size { get; } |
||||
public object? Value { get; } |
||||
public string Meaning { get; } |
||||
public IList<BitEntry>? RowDetails { get; } |
||||
|
||||
public Entry(int offset, object? value, int size, string member, string meaning, IList<BitEntry>? rowDetails = null) |
||||
{ |
||||
Member = member; |
||||
Offset = offset; |
||||
Size = size; |
||||
Value = value; |
||||
Meaning = meaning; |
||||
RowDetails = rowDetails; |
||||
} |
||||
} |
||||
|
||||
/// <summary>One bit (or bit-group) entry inside a flags-Entry's row-details strip.</summary>
|
||||
public sealed class BitEntry |
||||
{ |
||||
public bool Value { get; } |
||||
public string Meaning { get; } |
||||
|
||||
public BitEntry(bool value, string meaning) |
||||
{ |
||||
Value = value; |
||||
Meaning = meaning; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,133 @@
@@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Globalization; |
||||
using System.Linq; |
||||
using System.Reflection; |
||||
using System.Text; |
||||
|
||||
using ICSharpCode.Decompiler; |
||||
|
||||
using ILSpy.Languages; |
||||
|
||||
namespace ILSpy.Metadata |
||||
{ |
||||
/// <summary>
|
||||
/// Renders a list of row objects to <see cref="ITextOutput"/> as a fixed-width table —
|
||||
/// the Phase 1 stand-in for the DataGrid view. Column names come from
|
||||
/// <see cref="PropertyInfo.Name"/>; cell formatting respects
|
||||
/// <see cref="ColumnInfoAttribute.Format"/> and, for <see cref="Entry"/> rows, the
|
||||
/// per-row hex-width implied by <see cref="Entry.Size"/>. Each emitted line goes through
|
||||
/// <see cref="Language.WriteCommentLine"/> so the output sits cleanly inside the
|
||||
/// existing comment-prefixed text pipeline.
|
||||
/// </summary>
|
||||
public static class MetadataTextWriter |
||||
{ |
||||
public static void WriteTable<TRow>(Language language, ITextOutput output, IReadOnlyList<TRow> rows) |
||||
{ |
||||
ArgumentNullException.ThrowIfNull(language); |
||||
ArgumentNullException.ThrowIfNull(output); |
||||
ArgumentNullException.ThrowIfNull(rows); |
||||
|
||||
var props = typeof(TRow).GetProperties(BindingFlags.Public | BindingFlags.Instance) |
||||
.Where(p => p.GetIndexParameters().Length == 0 |
||||
&& p.PropertyType != typeof(IList<BitEntry>) |
||||
&& p.Name != nameof(Entry.RowDetails)) |
||||
.ToArray(); |
||||
if (props.Length == 0) |
||||
return; |
||||
|
||||
var formats = props.Select(p => p.GetCustomAttribute<ColumnInfoAttribute>()?.Format).ToArray(); |
||||
|
||||
// Materialise every cell as a string, so column widths can be computed in one pass.
|
||||
var cells = new string[rows.Count][]; |
||||
for (int r = 0; r < rows.Count; r++) |
||||
{ |
||||
cells[r] = new string[props.Length]; |
||||
for (int c = 0; c < props.Length; c++) |
||||
cells[r][c] = FormatCell(rows[r], props[c], formats[c]); |
||||
} |
||||
|
||||
var widths = new int[props.Length]; |
||||
for (int c = 0; c < props.Length; c++) |
||||
{ |
||||
widths[c] = props[c].Name.Length; |
||||
for (int r = 0; r < rows.Count; r++) |
||||
widths[c] = Math.Max(widths[c], cells[r][c].Length); |
||||
} |
||||
|
||||
language.WriteCommentLine(output, BuildLine(widths, props.Select(p => p.Name).ToArray())); |
||||
language.WriteCommentLine(output, BuildLine(widths, widths.Select(w => new string('-', w)).ToArray())); |
||||
for (int r = 0; r < rows.Count; r++) |
||||
language.WriteCommentLine(output, BuildLine(widths, cells[r])); |
||||
} |
||||
|
||||
static string BuildLine(int[] widths, string[] cells) |
||||
{ |
||||
var sb = new StringBuilder(); |
||||
for (int i = 0; i < cells.Length; i++) |
||||
{ |
||||
if (i > 0) |
||||
sb.Append(" "); |
||||
sb.Append(cells[i].PadRight(widths[i])); |
||||
} |
||||
return sb.ToString().TrimEnd(); |
||||
} |
||||
|
||||
static string FormatCell(object? row, PropertyInfo prop, string? format) |
||||
{ |
||||
var value = prop.GetValue(row); |
||||
if (value is null) |
||||
return ""; |
||||
|
||||
// Entry-shaped rows get special handling: Offset → 8-digit hex; Value → hex padded
|
||||
// to (Size * 2) digits. Phase 2 will hoist this onto a converter; Phase 1 keeps it
|
||||
// inline because the only consumer is this writer.
|
||||
if (row is Entry entry) |
||||
{ |
||||
if (prop.Name == nameof(Entry.Offset)) |
||||
return ((int)value).ToString("X8", CultureInfo.InvariantCulture); |
||||
if (prop.Name == nameof(Entry.Value) && entry.Size > 0) |
||||
return FormatHex(value, entry.Size * 2); |
||||
} |
||||
|
||||
if (!string.IsNullOrEmpty(format) && value is IFormattable formattable) |
||||
return formattable.ToString(format, CultureInfo.InvariantCulture); |
||||
|
||||
return value.ToString() ?? ""; |
||||
} |
||||
|
||||
static string FormatHex(object value, int width) |
||||
{ |
||||
string spec = "X" + width.ToString(CultureInfo.InvariantCulture); |
||||
return value switch { |
||||
ulong u => u.ToString(spec, CultureInfo.InvariantCulture), |
||||
long l => l.ToString(spec, CultureInfo.InvariantCulture), |
||||
uint ui => ui.ToString(spec, CultureInfo.InvariantCulture), |
||||
int i => i.ToString(spec, CultureInfo.InvariantCulture), |
||||
ushort us => us.ToString(spec, CultureInfo.InvariantCulture), |
||||
short s => s.ToString(spec, CultureInfo.InvariantCulture), |
||||
byte b => b.ToString(spec, CultureInfo.InvariantCulture), |
||||
sbyte sb => sb.ToString(spec, CultureInfo.InvariantCulture), |
||||
_ => value.ToString() ?? "", |
||||
}; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,114 @@
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Reflection.PortableExecutable; |
||||
|
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
|
||||
using ILSpy.Languages; |
||||
using ILSpy.TreeNodes; |
||||
|
||||
namespace ILSpy.Metadata |
||||
{ |
||||
/// <summary>
|
||||
/// PE Optional Header — image base, sizes, alignments, subsystem. Field widths flex
|
||||
/// between PE32 and PE32+ (Image Base / Stack & Heap reserves go from 4 → 8 bytes,
|
||||
/// Base Of Data drops out on PE32+).
|
||||
/// </summary>
|
||||
public sealed class OptionalHeaderTreeNode : ILSpyTreeNode |
||||
{ |
||||
readonly PEFile module; |
||||
|
||||
public OptionalHeaderTreeNode(PEFile module) |
||||
{ |
||||
this.module = module ?? throw new ArgumentNullException(nameof(module)); |
||||
} |
||||
|
||||
public override object Text => "Optional Header"; |
||||
public override object Icon => Images.Images.MetadataTable; |
||||
public override string ToString() => "Optional Header"; |
||||
|
||||
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) |
||||
{ |
||||
language.WriteCommentLine(output, "Optional Header"); |
||||
MetadataTextWriter.WriteTable(language, output, BuildEntries()); |
||||
} |
||||
|
||||
IReadOnlyList<Entry> BuildEntries() |
||||
{ |
||||
var headers = module.Reader.PEHeaders; |
||||
var reader = module.Reader.GetEntireImage().GetReader(headers.PEHeaderStartOffset, 128); |
||||
var header = headers.PEHeader!; |
||||
bool isPE32Plus = header.Magic == PEMagic.PE32Plus; |
||||
|
||||
var entries = new List<Entry>(); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadUInt16(), 2, "Magic", header.Magic.ToString())); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadByte(), 1, "Major Linker Version", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadByte(), 1, "Minor Linker Version", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "Code Size", "Size of the code (text) section, or the sum of all code sections if there are multiple sections.")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "Initialized Data Size", "Size of the initialized data section, or the sum of all initialized data sections if there are multiple data sections.")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "Uninitialized Data Size", "Size of the uninitialized data section, or the sum of all uninitialized data sections if there are multiple uninitialized data sections.")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "Entry Point RVA", "RVA of entry point, needs to point to bytes 0xFF 0x25 followed by the RVA in a section marked execute / read for EXEs or 0 for DLLs")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "Base Of Code", "RVA of the code section.")); |
||||
entries.Add(new Entry(isPE32Plus ? 0 : headers.PEHeaderStartOffset + reader.Offset, isPE32Plus ? 0UL : reader.ReadUInt32(), isPE32Plus ? 0 : 4, "Base Of Data", "PE32 only (not present in PE32Plus): RVA of the data section, relative to the Image Base.")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, isPE32Plus ? reader.ReadUInt64() : reader.ReadUInt32(), isPE32Plus ? 8 : 4, "Image Base", "Shall be a multiple of 0x10000.")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "Section Alignment", "Shall be greater than File Alignment.")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "File Alignment", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadUInt16(), 2, "Major OS Version", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadUInt16(), 2, "Minor OS Version", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadUInt16(), 2, "Major Image Version", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadUInt16(), 2, "Minor Image Version", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadUInt16(), 2, "Major Subsystem Version", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadUInt16(), 2, "Minor Subsystem Version", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadUInt32(), 4, "Win32VersionValue", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "Image Size", "Size, in bytes, of image, including all headers and padding; shall be a multiple of Section Alignment.")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "Header Size", "Combined size of MS-DOS Header, PE Header, PE Optional Header and padding; shall be a multiple of the file alignment.")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "File Checksum", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadUInt16(), 2, "Subsystem", header.Subsystem.ToString())); |
||||
ushort dllCharacteristics = reader.ReadUInt16(); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset - 2, dllCharacteristics, 2, "DLL Characteristics", header.DllCharacteristics.ToString(), new BitEntry[] { |
||||
new((dllCharacteristics & 0x0001) != 0, "<0001> Process Init (Reserved)"), |
||||
new((dllCharacteristics & 0x0002) != 0, "<0002> Process Term (Reserved)"), |
||||
new((dllCharacteristics & 0x0004) != 0, "<0004> Thread Init (Reserved)"), |
||||
new((dllCharacteristics & 0x0008) != 0, "<0008> Thread Term (Reserved)"), |
||||
new((dllCharacteristics & 0x0010) != 0, "<0010> Unused"), |
||||
new((dllCharacteristics & 0x0020) != 0, "<0020> Image can handle a high entropy 64-bit virtual address space (ASLR)"), |
||||
new((dllCharacteristics & 0x0040) != 0, "<0040> DLL can be relocated at load time"), |
||||
new((dllCharacteristics & 0x0080) != 0, "<0080> Code integrity checks are enforced"), |
||||
new((dllCharacteristics & 0x0100) != 0, "<0100> Image is NX compatible"), |
||||
new((dllCharacteristics & 0x0200) != 0, "<0200> Isolation aware, but do not isolate the image"), |
||||
new((dllCharacteristics & 0x0400) != 0, "<0400> Does not use structured exception handling (SEH)"), |
||||
new((dllCharacteristics & 0x0800) != 0, "<0800> Do not bind the image"), |
||||
new((dllCharacteristics & 0x1000) != 0, "<1000> Image must execute in an AppContainer"), |
||||
new((dllCharacteristics & 0x2000) != 0, "<2000> Driver is a WDM Driver"), |
||||
new((dllCharacteristics & 0x4000) != 0, "<4000> Image supports Control Flow Guard"), |
||||
new((dllCharacteristics & 0x8000) != 0, "<8000> Image is Terminal Server aware"), |
||||
})); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, isPE32Plus ? reader.ReadUInt64() : reader.ReadUInt32(), isPE32Plus ? 8 : 4, "Stack Reserve Size", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, isPE32Plus ? reader.ReadUInt64() : reader.ReadUInt32(), isPE32Plus ? 8 : 4, "Stack Commit Size", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, isPE32Plus ? reader.ReadUInt64() : reader.ReadUInt32(), isPE32Plus ? 8 : 4, "Heap Reserve Size", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, isPE32Plus ? reader.ReadUInt64() : reader.ReadUInt32(), isPE32Plus ? 8 : 4, "Heap Commit Size", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadUInt32(), 4, "Loader Flags", "")); |
||||
entries.Add(new Entry(headers.PEHeaderStartOffset + reader.Offset, reader.ReadInt32(), 4, "Number of Data Directories", "")); |
||||
return entries; |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue