From 167928b46be0507fd2f0ce6b46631ffe7367a383 Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 3 Jun 2024 22:44:41 +0200 Subject: [PATCH 1/8] Remove IPEFile interface. --- src/AsmResolver.DotNet/ModuleDefinition.cs | 4 +- src/AsmResolver.PE.File/IPEFile.cs | 176 ------------------ src/AsmResolver.PE.File/PEFile.cs | 122 +++++++++--- src/AsmResolver.PE.File/PESegmentReference.cs | 4 +- .../Builder/TrampolineTableBuffer.cs | 2 +- .../Builder/UnmanagedPEFileBuilder.cs | 4 +- .../DotNet/StrongName/StrongNameSigner.cs | 2 +- src/AsmResolver.PE/IPEImage.cs | 2 +- src/AsmResolver.PE/PEImage.cs | 24 +-- src/AsmResolver.PE/PEReaderContext.cs | 7 +- src/AsmResolver.PE/SerializedPEImage.cs | 4 +- 11 files changed, 125 insertions(+), 226 deletions(-) delete mode 100644 src/AsmResolver.PE.File/IPEFile.cs diff --git a/src/AsmResolver.DotNet/ModuleDefinition.cs b/src/AsmResolver.DotNet/ModuleDefinition.cs index cf4ba3151..feb6b5dc5 100644 --- a/src/AsmResolver.DotNet/ModuleDefinition.cs +++ b/src/AsmResolver.DotNet/ModuleDefinition.cs @@ -114,7 +114,7 @@ public static ModuleDefinition FromFile(IInputFile file, ModuleReaderParameters /// The portable executable file to load. /// The module. /// Occurs when the image does not contain a valid .NET metadata directory. - public static ModuleDefinition FromFile(IPEFile file) => FromFile(file, new ModuleReaderParameters()); + public static ModuleDefinition FromFile(PEFile file) => FromFile(file, new ModuleReaderParameters()); /// /// Reads a .NET module from the provided input file. @@ -123,7 +123,7 @@ public static ModuleDefinition FromFile(IInputFile file, ModuleReaderParameters /// The parameters to use while reading the module. /// The module. /// Occurs when the image does not contain a valid .NET metadata directory. - public static ModuleDefinition FromFile(IPEFile file, ModuleReaderParameters readerParameters) => + public static ModuleDefinition FromFile(PEFile file, ModuleReaderParameters readerParameters) => FromImage(PEImage.FromFile(file, readerParameters.PEReaderParameters), readerParameters); /// diff --git a/src/AsmResolver.PE.File/IPEFile.cs b/src/AsmResolver.PE.File/IPEFile.cs deleted file mode 100644 index e2469c1e4..000000000 --- a/src/AsmResolver.PE.File/IPEFile.cs +++ /dev/null @@ -1,176 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using AsmResolver.IO; - -namespace AsmResolver.PE.File -{ - /// - /// Provides a writable implementation of the interface. - /// - public interface IPEFile : ISegmentReferenceFactory, IOffsetConverter - { - /// - /// When this PE file was read from the disk, gets the file path to the PE file. - /// - string? FilePath - { - get; - } - - /// - /// Gets or sets the DOS header of the PE file. - /// - DosHeader DosHeader - { - get; - } - - /// - /// Gets or sets the COFF file header of the portable executable (PE) file. - /// - FileHeader FileHeader - { - get; - } - - /// - /// Gets or sets the optional header of the portable executable (PE) file. - /// - OptionalHeader OptionalHeader - { - get; - } - - /// - /// Gets a collection of sections present in the portable executable (PE) file. - /// - IList Sections - { - get; - } - - /// - /// Gets a value indicating the mapping mode of the PE file. If the PE file is in its mapped form, - /// then every offset of all segments in the PE file will be equal to the physical memory address. - /// If the file is in its unmapped form, the offsets will be equal to the file offset. - /// - PEMappingMode MappingMode - { - get; - } - - /// - /// Gets or sets the padding data in between the last section header and the first section. - /// - public ISegment? ExtraSectionData - { - get; - set; - } - - /// - /// Gets or sets the data appended to the end of the file (EoF), if available. - /// - public ISegment? EofData - { - get; - set; - } - - /// - /// Finds the section containing the provided virtual address. - /// - /// The virtual address. - /// The section containing the virtual address. - /// Occurs when the virtual address does not fall within any of the sections. - PESection GetSectionContainingRva(uint rva); - - /// - /// Attempts to find the section containing the provided virtual address. - /// - /// The virtual address. - /// The section that was found. - /// true if the section was found, false otherwise. - bool TryGetSectionContainingRva(uint rva, [NotNullWhen(true)] out PESection? section); - - /// - /// Obtains a reader that spans the provided data directory. - /// - /// The data directory to read. - /// The reader. - BinaryStreamReader CreateDataDirectoryReader(DataDirectory dataDirectory); - - /// - /// Attempts to create a reader that spans the provided data directory. - /// - /// The data directory to read. - /// The reader that was created. - /// true if the reader was created successfully, false otherwise. - bool TryCreateDataDirectoryReader(DataDirectory dataDirectory, out BinaryStreamReader reader); - - /// - /// Creates a new reader at the provided virtual address. - /// - /// The virtual address to start reading at. - /// The reader. - BinaryStreamReader CreateReaderAtRva(uint rva); - - /// - /// Attempts to create a new reader at the provided virtual address. - /// - /// The virtual address to start reading at. - /// The reader that was created. - /// true if the reader was created successfully, false otherwise. - bool TryCreateReaderAtRva(uint rva, out BinaryStreamReader reader); - - /// - /// Creates a new reader of a chunk of data at the provided virtual address. - /// - /// The virtual address to start reading at. - /// The number of bytes in the chunk. - /// The reader. - BinaryStreamReader CreateReaderAtRva(uint rva, uint size); - - /// - /// Attempts to create a new reader of a chunk of data at the provided virtual address. - /// - /// The virtual address to start reading at. - /// The number of bytes in the chunk. - /// The reader that was created. - /// true if the reader was created successfully, false otherwise. - bool TryCreateReaderAtRva(uint rva, uint size, out BinaryStreamReader reader); - - /// - /// Creates a new reader at the provided file offset. - /// - /// The file offset to start reading at. - /// The reader. - BinaryStreamReader CreateReaderAtFileOffset(uint fileOffset); - - /// - /// Attempts to create a new reader at the provided file offset. - /// - /// The file offset to start reading at. - /// The reader that was created. - /// true if the reader was created successfully, false otherwise. - bool TryCreateReaderAtFileOffset(uint fileOffset, out BinaryStreamReader reader); - - /// - /// Creates a new reader of a chunk of data at the provided file offset. - /// - /// The file offset to start reading at. - /// The number of bytes in the chunk. - /// The reader. - BinaryStreamReader CreateReaderAtFileOffset(uint fileOffset, uint size); - - /// - /// Attempts to create a new reader of a chunk of data at the provided file offset. - /// - /// The file offset to start reading at. - /// The number of bytes in the chunk. - /// The reader that was created. - /// true if the reader was created successfully, false otherwise. - bool TryCreateReaderAtFileOffset(uint fileOffset, uint size, out BinaryStreamReader reader); - } -} diff --git a/src/AsmResolver.PE.File/PEFile.cs b/src/AsmResolver.PE.File/PEFile.cs index 0eb2b7ff8..889ec40be 100644 --- a/src/AsmResolver.PE.File/PEFile.cs +++ b/src/AsmResolver.PE.File/PEFile.cs @@ -12,7 +12,7 @@ namespace AsmResolver.PE.File /// Models a file using the portable executable (PE) file format. It provides access to various PE headers, as well /// as the raw contents of each section present in the file. /// - public class PEFile : IPEFile + public class PEFile : ISegmentReferenceFactory, IOffsetConverter { /// /// Indicates a valid NT header signature. @@ -47,35 +47,45 @@ public PEFile(DosHeader dosHeader, FileHeader fileHeader, OptionalHeader optiona MappingMode = PEMappingMode.Unmapped; } - /// + /// + /// When this PE file was read from the disk, gets the file path to the PE file. + /// public string? FilePath { get; protected set; } - /// + /// + /// Gets or sets the DOS header of the PE file. + /// public DosHeader DosHeader { get; set; } - /// + /// + /// Gets or sets the COFF file header of the portable executable (PE) file. + /// public FileHeader FileHeader { get; set; } - /// + /// + /// Gets or sets the optional header of the portable executable (PE) file. + /// public OptionalHeader OptionalHeader { get; set; } - /// + /// + /// Gets a collection of sections present in the portable executable (PE) file. + /// public IList Sections { get @@ -86,21 +96,29 @@ public IList Sections } } - /// + /// + /// Gets a value indicating the mapping mode of the PE file. If the PE file is in its mapped form, + /// then every offset of all segments in the PE file will be equal to the physical memory address. + /// If the file is in its unmapped form, the offsets will be equal to the file offset. + /// public PEMappingMode MappingMode { get; protected set; } - /// + /// + /// Gets or sets the padding data in between the last section header and the first section. + /// public ISegment? ExtraSectionData { get => _extraSectionData.GetValue(this); set => _extraSectionData.SetValue(value); } - /// + /// + /// Gets or sets the data appended to the end of the file (EoF), if available. + /// public ISegment? EofData { get => _eofData.GetValue(this); @@ -142,8 +160,7 @@ public static PEFile FromFile(IInputFile file) /// The HINSTANCE or base address of the module. /// The PE file that was read. /// Occurs when the file does not follow the PE file format. - public static unsafe PEFile FromModuleBaseAddress(IntPtr hInstance) - => FromModuleBaseAddress(hInstance, PEMappingMode.Mapped); + public static PEFile FromModuleBaseAddress(IntPtr hInstance) => FromModuleBaseAddress(hInstance, PEMappingMode.Mapped); /// /// Reads a PE file starting at the provided module base address (HINSTANCE). @@ -232,7 +249,12 @@ public bool TryGetSectionContainingOffset(ulong fileOffset, [NotNullWhen(true)] return false; } - /// + /// + /// Finds the section containing the provided virtual address. + /// + /// The virtual address. + /// The section containing the virtual address. + /// Occurs when the virtual address does not fall within any of the sections. public PESection GetSectionContainingRva(uint rva) { if (!TryGetSectionContainingRva(rva, out var section)) @@ -240,7 +262,12 @@ public PESection GetSectionContainingRva(uint rva) return section; } - /// + /// + /// Attempts to find the section containing the provided virtual address. + /// + /// The virtual address. + /// The section that was found. + /// true if the section was found, false otherwise. public bool TryGetSectionContainingRva(uint rva, [NotNullWhen(true)] out PESection? section) { var sections = Sections; @@ -258,7 +285,11 @@ public bool TryGetSectionContainingRva(uint rva, [NotNullWhen(true)] out PESect return false; } - /// + /// + /// Obtains a reader that spans the provided data directory. + /// + /// The data directory to read. + /// The reader. public BinaryStreamReader CreateDataDirectoryReader(DataDirectory dataDirectory) { var section = GetSectionContainingRva(dataDirectory.VirtualAddress); @@ -266,7 +297,12 @@ public BinaryStreamReader CreateDataDirectoryReader(DataDirectory dataDirectory) return section.CreateReader(fileOffset, dataDirectory.Size); } - /// + /// + /// Attempts to create a reader that spans the provided data directory. + /// + /// The data directory to read. + /// The reader that was created. + /// true if the reader was created successfully, false otherwise. public bool TryCreateDataDirectoryReader(DataDirectory dataDirectory, out BinaryStreamReader reader) { if (TryGetSectionContainingRva(dataDirectory.VirtualAddress, out var section)) @@ -280,7 +316,11 @@ public bool TryCreateDataDirectoryReader(DataDirectory dataDirectory, out Binary return false; } - /// + /// + /// Creates a new reader at the provided file offset. + /// + /// The file offset to start reading at. + /// The reader. public BinaryStreamReader CreateReaderAtFileOffset(uint fileOffset) { return !TryCreateReaderAtFileOffset(fileOffset, out var reader) @@ -288,7 +328,12 @@ public BinaryStreamReader CreateReaderAtFileOffset(uint fileOffset) : reader; } - /// + /// + /// Attempts to create a new reader at the provided file offset. + /// + /// The file offset to start reading at. + /// The reader that was created. + /// true if the reader was created successfully, false otherwise. public bool TryCreateReaderAtFileOffset(uint fileOffset, out BinaryStreamReader reader) { if (TryGetSectionContainingOffset(fileOffset, out var section)) @@ -309,14 +354,25 @@ public bool TryCreateReaderAtFileOffset(uint fileOffset, out BinaryStreamReader return false; } - /// + /// + /// Creates a new reader of a chunk of data at the provided file offset. + /// + /// The file offset to start reading at. + /// The number of bytes in the chunk. + /// The reader. public BinaryStreamReader CreateReaderAtFileOffset(uint fileOffset, uint size) { var section = GetSectionContainingOffset(fileOffset); return section.CreateReader(fileOffset, size); } - /// + /// + /// Attempts to create a new reader of a chunk of data at the provided file offset. + /// + /// The file offset to start reading at. + /// The number of bytes in the chunk. + /// The reader that was created. + /// true if the reader was created successfully, false otherwise. public bool TryCreateReaderAtFileOffset(uint fileOffset, uint size, out BinaryStreamReader reader) { if (TryGetSectionContainingOffset(fileOffset, out var section)) @@ -337,14 +393,23 @@ public bool TryCreateReaderAtFileOffset(uint fileOffset, uint size, out BinarySt return false; } - /// + /// + /// Creates a new reader at the provided virtual address. + /// + /// The virtual address to start reading at. + /// The reader. public BinaryStreamReader CreateReaderAtRva(uint rva) { var section = GetSectionContainingRva(rva); return section.CreateReader(section.RvaToFileOffset(rva)); } - /// + /// + /// Attempts to create a new reader at the provided virtual address. + /// + /// The virtual address to start reading at. + /// The reader that was created. + /// true if the reader was created successfully, false otherwise. public bool TryCreateReaderAtRva(uint rva, out BinaryStreamReader reader) { if (TryGetSectionContainingRva(rva, out var section)) @@ -357,14 +422,25 @@ public bool TryCreateReaderAtRva(uint rva, out BinaryStreamReader reader) return false; } - /// + /// + /// Creates a new reader of a chunk of data at the provided virtual address. + /// + /// The virtual address to start reading at. + /// The number of bytes in the chunk. + /// The reader. public BinaryStreamReader CreateReaderAtRva(uint rva, uint size) { var section = GetSectionContainingRva(rva); return section.CreateReader(section.RvaToFileOffset(rva), size); } - /// + /// + /// Attempts to create a new reader of a chunk of data at the provided virtual address. + /// + /// The virtual address to start reading at. + /// The number of bytes in the chunk. + /// The reader that was created. + /// true if the reader was created successfully, false otherwise. public bool TryCreateReaderAtRva(uint rva, uint size, out BinaryStreamReader reader) { if (TryGetSectionContainingRva(rva, out var section)) diff --git a/src/AsmResolver.PE.File/PESegmentReference.cs b/src/AsmResolver.PE.File/PESegmentReference.cs index 2e0117ccb..a3dc82c86 100644 --- a/src/AsmResolver.PE.File/PESegmentReference.cs +++ b/src/AsmResolver.PE.File/PESegmentReference.cs @@ -8,14 +8,14 @@ namespace AsmResolver.PE.File /// public sealed class PESegmentReference : ISegmentReference { - private readonly IPEFile _peFile; + private readonly PEFile _peFile; /// /// Creates a new PE reference. /// /// The underlying PE file. /// The virtual address of the segment. - internal PESegmentReference(IPEFile peFile, uint rva) + internal PESegmentReference(PEFile peFile, uint rva) { _peFile = peFile; Rva = rva; diff --git a/src/AsmResolver.PE/Builder/TrampolineTableBuffer.cs b/src/AsmResolver.PE/Builder/TrampolineTableBuffer.cs index dbe6a65d7..bff5fb30f 100644 --- a/src/AsmResolver.PE/Builder/TrampolineTableBuffer.cs +++ b/src/AsmResolver.PE/Builder/TrampolineTableBuffer.cs @@ -104,7 +104,7 @@ private void EnsureAddressTableInitializerAdded() /// Applies the trampoline address patches to the provided PE file. /// /// The file to patch. - public void ApplyPatches(IPEFile file) => ApplyPatches(file.Sections); + public void ApplyPatches(PEFile file) => ApplyPatches(file.Sections); /// /// Applies the trampoline address patches to the provided PE file sections. diff --git a/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs b/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs index bbef75c5a..1825e4ca4 100644 --- a/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs +++ b/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs @@ -69,7 +69,7 @@ public UnmanagedPEFileBuilder(IErrorListener errorListener) /// /// The error listener to use. /// The template file to base the resulting file on. - public UnmanagedPEFileBuilder(IErrorListener errorListener, IPEFile? baseFile) + public UnmanagedPEFileBuilder(IErrorListener errorListener, PEFile? baseFile) { ErrorListener = errorListener; BaseFile = baseFile; @@ -87,7 +87,7 @@ public IErrorListener ErrorListener /// /// Gets or sets the template file to base the resulting file on. /// - public IPEFile? BaseFile + public PEFile? BaseFile { get; set; diff --git a/src/AsmResolver.PE/DotNet/StrongName/StrongNameSigner.cs b/src/AsmResolver.PE/DotNet/StrongName/StrongNameSigner.cs index 9b962a66d..977d37643 100644 --- a/src/AsmResolver.PE/DotNet/StrongName/StrongNameSigner.cs +++ b/src/AsmResolver.PE/DotNet/StrongName/StrongNameSigner.cs @@ -73,7 +73,7 @@ public void SignImage(Stream imageStream, AssemblyHashAlgorithm hashAlgorithm) private byte[] GetHashToSign( Stream imageStream, - IPEFile file, + PEFile file, IPEImage image, AssemblyHashAlgorithm hashAlgorithm) { diff --git a/src/AsmResolver.PE/IPEImage.cs b/src/AsmResolver.PE/IPEImage.cs index cd3a9ae9d..01951b655 100644 --- a/src/AsmResolver.PE/IPEImage.cs +++ b/src/AsmResolver.PE/IPEImage.cs @@ -29,7 +29,7 @@ public interface IPEImage /// while also using the PE image object can have unwanted side effects. /// /// - IPEFile? PEFile + PEFile? PEFile { get; } diff --git a/src/AsmResolver.PE/PEImage.cs b/src/AsmResolver.PE/PEImage.cs index d591a4583..3cec90ead 100644 --- a/src/AsmResolver.PE/PEImage.cs +++ b/src/AsmResolver.PE/PEImage.cs @@ -37,7 +37,7 @@ public class PEImage : IPEImage /// The /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromFile(string filePath) => FromFile(File.PEFile.FromFile(filePath)); + public static IPEImage FromFile(string filePath) => FromFile(PEFile.FromFile(filePath)); /// /// Opens a PE image from a specific file on the disk. @@ -47,7 +47,7 @@ public class PEImage : IPEImage /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. public static IPEImage FromFile(string filePath, PEReaderParameters readerParameters) => - FromFile(File.PEFile.FromFile(readerParameters.FileService.OpenFile(filePath)), readerParameters); + FromFile(PEFile.FromFile(readerParameters.FileService.OpenFile(filePath)), readerParameters); /// /// Opens a PE image from a buffer. @@ -55,7 +55,7 @@ public static IPEImage FromFile(string filePath, PEReaderParameters readerParame /// The bytes to interpret. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromBytes(byte[] bytes) => FromFile(File.PEFile.FromBytes(bytes)); + public static IPEImage FromBytes(byte[] bytes) => FromFile(PEFile.FromBytes(bytes)); /// /// Opens a PE image from a buffer. @@ -65,7 +65,7 @@ public static IPEImage FromFile(string filePath, PEReaderParameters readerParame /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. public static IPEImage FromBytes(byte[] bytes, PEReaderParameters readerParameters) => - FromFile(File.PEFile.FromBytes(bytes), readerParameters); + FromFile(PEFile.FromBytes(bytes), readerParameters); /// /// Reads a mapped PE image starting at the provided module base address (HINSTANCE). @@ -84,7 +84,7 @@ public static IPEImage FromModuleBaseAddress(IntPtr hInstance) => /// The PE image that was read. /// Occurs when the file does not follow the PE file format. public static IPEImage FromModuleBaseAddress(IntPtr hInstance, PEReaderParameters readerParameters) => - FromFile(File.PEFile.FromModuleBaseAddress(hInstance), readerParameters); + FromFile(PEFile.FromModuleBaseAddress(hInstance), readerParameters); /// /// Reads a PE image starting at the provided module base address (HINSTANCE). @@ -95,7 +95,7 @@ public static IPEImage FromModuleBaseAddress(IntPtr hInstance, PEReaderParameter /// The PE image that was read. /// Occurs when the file does not follow the PE file format. public static IPEImage FromModuleBaseAddress(IntPtr hInstance, PEMappingMode mode, PEReaderParameters readerParameters) => - FromFile(File.PEFile.FromModuleBaseAddress(hInstance, mode), readerParameters); + FromFile(PEFile.FromModuleBaseAddress(hInstance, mode), readerParameters); /// /// Reads a PE image from the provided data source. @@ -126,7 +126,7 @@ public static IPEImage FromDataSource(IDataSource dataSource, PEMappingMode mode /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. public static IPEImage FromReader(in BinaryStreamReader reader, PEMappingMode mode = PEMappingMode.Unmapped) => - FromFile(File.PEFile.FromReader(reader, mode)); + FromFile(PEFile.FromReader(reader, mode)); /// /// Opens a PE image from an input stream. @@ -137,7 +137,7 @@ public static IPEImage FromReader(in BinaryStreamReader reader, PEMappingMode mo /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. public static IPEImage FromReader(in BinaryStreamReader reader, PEMappingMode mode, PEReaderParameters readerParameters) => - FromFile(File.PEFile.FromReader(reader, mode), readerParameters); + FromFile(PEFile.FromReader(reader, mode), readerParameters); /// /// Opens a PE image from an input file object. @@ -155,7 +155,7 @@ public static IPEImage FromReader(in BinaryStreamReader reader, PEMappingMode mo /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. public static IPEImage FromFile(IInputFile inputFile, PEReaderParameters readerParameters) => - FromFile(File.PEFile.FromFile(inputFile), readerParameters); + FromFile(PEFile.FromFile(inputFile), readerParameters); /// /// Opens a PE image from a PE file object. @@ -163,7 +163,7 @@ public static IPEImage FromFile(IInputFile inputFile, PEReaderParameters readerP /// The PE file object. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromFile(IPEFile peFile) => FromFile(peFile, new PEReaderParameters()); + public static IPEImage FromFile(PEFile peFile) => FromFile(peFile, new PEReaderParameters()); /// /// Opens a PE image from a PE file object. @@ -172,7 +172,7 @@ public static IPEImage FromFile(IInputFile inputFile, PEReaderParameters readerP /// The parameters to use while reading the PE image. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromFile(IPEFile peFile, PEReaderParameters readerParameters) => + public static IPEImage FromFile(PEFile peFile, PEReaderParameters readerParameters) => new SerializedPEImage(peFile, readerParameters); /// @@ -188,7 +188,7 @@ public PEImage() } /// - public virtual IPEFile? PEFile => null; + public virtual PEFile? PEFile => null; /// public string? FilePath diff --git a/src/AsmResolver.PE/PEReaderContext.cs b/src/AsmResolver.PE/PEReaderContext.cs index 7d8111b47..c3379d862 100644 --- a/src/AsmResolver.PE/PEReaderContext.cs +++ b/src/AsmResolver.PE/PEReaderContext.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.CompilerServices; using AsmResolver.PE.File; namespace AsmResolver.PE @@ -14,7 +13,7 @@ public class PEReaderContext : IErrorListener /// Creates a new instance of the class. /// /// The original PE file. - public PEReaderContext(IPEFile file) + public PEReaderContext(PEFile file) : this(file, new PEReaderParameters()) { } @@ -24,7 +23,7 @@ public PEReaderContext(IPEFile file) /// /// The original PE file. /// The reader parameters. - public PEReaderContext(IPEFile file, PEReaderParameters parameters) + public PEReaderContext(PEFile file, PEReaderParameters parameters) { File = file; Parameters = parameters; @@ -33,7 +32,7 @@ public PEReaderContext(IPEFile file, PEReaderParameters parameters) /// /// Gets the original PE file that is being parsed. /// - public IPEFile File + public PEFile File { get; } diff --git a/src/AsmResolver.PE/SerializedPEImage.cs b/src/AsmResolver.PE/SerializedPEImage.cs index 4f8870da6..778af4ab1 100644 --- a/src/AsmResolver.PE/SerializedPEImage.cs +++ b/src/AsmResolver.PE/SerializedPEImage.cs @@ -25,7 +25,7 @@ public class SerializedPEImage : PEImage /// /// The file to base the image from. /// The parameters to use while reading the PE image. - public SerializedPEImage(IPEFile peFile, PEReaderParameters readerParameters) + public SerializedPEImage(PEFile peFile, PEReaderParameters readerParameters) { PEFile = peFile ?? throw new ArgumentNullException(nameof(peFile)); ReaderContext = new PEReaderContext(peFile, readerParameters); @@ -43,7 +43,7 @@ public SerializedPEImage(IPEFile peFile, PEReaderParameters readerParameters) } /// - public override IPEFile PEFile + public override PEFile PEFile { get; } From 61b05f63ce1c5b948d14cd256cda1a39f63c2d7b Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 3 Jun 2024 23:33:25 +0200 Subject: [PATCH 2/8] Remove IPEImage interface. --- src/AsmResolver.DotNet/AssemblyDefinition.cs | 4 +- .../Builder/PEImageBuildResult.cs | 6 +- .../Bundles/BundlerParameters.cs | 4 +- src/AsmResolver.DotNet/ModuleDefinition.cs | 10 +- .../Serialized/ModuleReaderContext.cs | 4 +- .../Serialized/SerializedModuleDefinition.cs | 2 +- src/AsmResolver.PE/Builder/IPEFileBuilder.cs | 4 +- .../Builder/ManagedPEFileBuilder.cs | 10 +- src/AsmResolver.PE/Builder/PEFileBuilder.cs | 6 +- .../Builder/PEFileBuilderContext.cs | 4 +- .../Builder/UnmanagedPEFileBuilder.cs | 10 +- .../Metadata/Tables/TypeReferenceHash.cs | 5 +- .../DotNet/StrongName/StrongNameSigner.cs | 2 +- src/AsmResolver.PE/IPEImage.cs | 218 ------------------ src/AsmResolver.PE/Imports/ImportHash.cs | 4 +- src/AsmResolver.PE/PEImage.cs | 147 +++++++++--- src/AsmResolver.PE/Platforms/Amd64Platform.cs | 2 +- src/AsmResolver.PE/Platforms/I386Platform.cs | 2 +- src/AsmResolver.PE/Platforms/Platform.cs | 2 +- .../Code/Native/NativeMethodBodyTest.cs | 2 +- .../Builder/MixedModeAssemblyTest.cs | 3 +- .../Debug/DebugDataEntryTest.cs | 2 +- .../DotNet/Metadata/MetadataTest.cs | 2 +- .../ReadyToRun/ReadyToRunDirectoryTest.cs | 2 +- .../VTableFixups/VTableFixupsDirectoryTest.cs | 2 +- .../Exports/ExportDirectoryTest.cs | 2 +- 26 files changed, 157 insertions(+), 304 deletions(-) delete mode 100644 src/AsmResolver.PE/IPEImage.cs diff --git a/src/AsmResolver.DotNet/AssemblyDefinition.cs b/src/AsmResolver.DotNet/AssemblyDefinition.cs index d899fb262..08fd7fd6e 100644 --- a/src/AsmResolver.DotNet/AssemblyDefinition.cs +++ b/src/AsmResolver.DotNet/AssemblyDefinition.cs @@ -113,7 +113,7 @@ public static AssemblyDefinition FromReader(in BinaryStreamReader reader, PEMapp /// The image containing the .NET metadata. /// The module. /// Occurs when the image does not contain a valid .NET metadata directory. - public static AssemblyDefinition FromImage(IPEImage peImage) => + public static AssemblyDefinition FromImage(PEImage peImage) => FromImage(peImage, new ModuleReaderParameters(Path.GetDirectoryName(peImage.FilePath))); /// @@ -123,7 +123,7 @@ public static AssemblyDefinition FromImage(IPEImage peImage) => /// The parameters to use while reading the assembly. /// The module. /// Occurs when the image does not contain a valid .NET metadata directory. - public static AssemblyDefinition FromImage(IPEImage peImage, ModuleReaderParameters readerParameters) => + public static AssemblyDefinition FromImage(PEImage peImage, ModuleReaderParameters readerParameters) => ModuleDefinition.FromImage(peImage, readerParameters).Assembly ?? throw new BadImageFormatException("The provided PE image does not contain an assembly manifest."); diff --git a/src/AsmResolver.DotNet/Builder/PEImageBuildResult.cs b/src/AsmResolver.DotNet/Builder/PEImageBuildResult.cs index 928614a5a..cdc3cb65d 100644 --- a/src/AsmResolver.DotNet/Builder/PEImageBuildResult.cs +++ b/src/AsmResolver.DotNet/Builder/PEImageBuildResult.cs @@ -16,7 +16,7 @@ public class PEImageBuildResult /// The diagnostics that were collected during the construction of the image. /// An object that maps metadata members to their newly assigned tokens. [Obsolete] - public PEImageBuildResult(IPEImage? image, DiagnosticBag diagnosticBag, ITokenMapping tokenMapping) + public PEImageBuildResult(PEImage? image, DiagnosticBag diagnosticBag, ITokenMapping tokenMapping) { ConstructedImage = image; ErrorListener = diagnosticBag ?? throw new ArgumentNullException(nameof(diagnosticBag)); @@ -29,7 +29,7 @@ public PEImageBuildResult(IPEImage? image, DiagnosticBag diagnosticBag, ITokenMa /// The constructed image, or null if the construction failed. /// The diagnostics that were collected during the construction of the image. /// An object that maps metadata members to their newly assigned tokens. - public PEImageBuildResult(IPEImage? image, IErrorListener errorListener, ITokenMapping tokenMapping) + public PEImageBuildResult(PEImage? image, IErrorListener errorListener, ITokenMapping tokenMapping) { ConstructedImage = image; ErrorListener = errorListener ?? throw new ArgumentNullException(nameof(errorListener)); @@ -39,7 +39,7 @@ public PEImageBuildResult(IPEImage? image, IErrorListener errorListener, ITokenM /// /// Gets the constructed image, or null if the construction failed. /// - public IPEImage? ConstructedImage + public PEImage? ConstructedImage { get; } diff --git a/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs b/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs index b98fad9e8..b0b78130f 100644 --- a/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs +++ b/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs @@ -135,7 +135,7 @@ imageToCopyHeadersFrom is not null /// file that hosts the CLR, or the original AppHost file the bundle was extracted from. /// [Obsolete("Use BundlerParameters::FromTemplate instead.")] - public BundlerParameters(byte[] appHostTemplate, string appBinaryPath, IPEImage? imageToCopyHeadersFrom) + public BundlerParameters(byte[] appHostTemplate, string appBinaryPath, PEImage? imageToCopyHeadersFrom) : this( appHostTemplate, appBinaryPath, @@ -325,7 +325,7 @@ public static BundlerParameters FromTemplate(byte[] appHostTemplate, string appB /// The image to copy the PE headers and Win32 resources from. This is typically the original native executable /// file that hosts the CLR, or the original AppHost file the bundle was extracted from. /// - public static BundlerParameters FromTemplate(byte[] appHostTemplate, string appBinaryPath, IPEImage? imageToCopyHeadersFrom) + public static BundlerParameters FromTemplate(byte[] appHostTemplate, string appBinaryPath, PEImage? imageToCopyHeadersFrom) { return new BundlerParameters { diff --git a/src/AsmResolver.DotNet/ModuleDefinition.cs b/src/AsmResolver.DotNet/ModuleDefinition.cs index feb6b5dc5..b32628e7f 100644 --- a/src/AsmResolver.DotNet/ModuleDefinition.cs +++ b/src/AsmResolver.DotNet/ModuleDefinition.cs @@ -235,7 +235,7 @@ public static ModuleDefinition FromReader(in BinaryStreamReader reader, PEMappin /// The image containing the .NET metadata. /// The module. /// Occurs when the image does not contain a valid .NET metadata directory. - public static ModuleDefinition FromImage(IPEImage peImage) + public static ModuleDefinition FromImage(PEImage peImage) { var moduleParameters = new ModuleReaderParameters(Path.GetDirectoryName(peImage.FilePath)) { @@ -254,7 +254,7 @@ public static ModuleDefinition FromImage(IPEImage peImage) /// The parameters to use while reading the module. /// The module. /// Occurs when the image does not contain a valid .NET data directory. - public static ModuleDefinition FromImage(IPEImage peImage, ModuleReaderParameters readerParameters) => + public static ModuleDefinition FromImage(PEImage peImage, ModuleReaderParameters readerParameters) => new SerializedModuleDefinition(peImage, readerParameters); // Disable non-nullable property initialization warnings for the CorLibTypeFactory, RuntimeContext and @@ -1311,7 +1311,7 @@ public void Write(IBinaryStreamWriter writer, IPEImageBuilder imageBuilder, IPEF /// /// IPEImage built using by default /// Occurs when the construction of the image threw exceptions. - public IPEImage ToPEImage() => ToPEImage(new ManagedPEImageBuilder(), true); + public PEImage ToPEImage() => ToPEImage(new ManagedPEImageBuilder(), true); /// /// Rebuilds the .NET module to a portable executable file and returns the IPEImage. @@ -1325,7 +1325,7 @@ public void Write(IBinaryStreamWriter writer, IPEImageBuilder imageBuilder, IPEF /// /// Occurs when the construction of the PE image failed completely. /// - public IPEImage ToPEImage(IPEImageBuilder imageBuilder) => ToPEImage(imageBuilder, true); + public PEImage ToPEImage(IPEImageBuilder imageBuilder) => ToPEImage(imageBuilder, true); /// /// Rebuilds the .NET module to a portable executable file and returns the IPEImage. @@ -1342,7 +1342,7 @@ public void Write(IBinaryStreamWriter writer, IPEImageBuilder imageBuilder, IPEF /// /// Occurs when the construction of the PE image failed completely. /// - public IPEImage ToPEImage(IPEImageBuilder imageBuilder, bool throwOnNonFatalError) + public PEImage ToPEImage(IPEImageBuilder imageBuilder, bool throwOnNonFatalError) { var result = imageBuilder.CreateImage(this); diff --git a/src/AsmResolver.DotNet/Serialized/ModuleReaderContext.cs b/src/AsmResolver.DotNet/Serialized/ModuleReaderContext.cs index f3414b439..669cfad8d 100644 --- a/src/AsmResolver.DotNet/Serialized/ModuleReaderContext.cs +++ b/src/AsmResolver.DotNet/Serialized/ModuleReaderContext.cs @@ -16,7 +16,7 @@ public class ModuleReaderContext : IErrorListener /// The original PE image to read from. /// The root module object. /// The module reader parameters. - public ModuleReaderContext(IPEImage image, SerializedModuleDefinition parentModule, ModuleReaderParameters parameters) + public ModuleReaderContext(PEImage image, SerializedModuleDefinition parentModule, ModuleReaderParameters parameters) { Image = image ?? throw new ArgumentNullException(nameof(image)); ParentModule = parentModule ?? throw new ArgumentNullException(nameof(parentModule)); @@ -70,7 +70,7 @@ public ModuleReaderContext(IPEImage image, SerializedModuleDefinition parentModu /// /// Gets the original PE image to read from. /// - public IPEImage Image + public PEImage Image { get; } diff --git a/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs b/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs index 43fff7283..f1f70dac1 100644 --- a/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs +++ b/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs @@ -26,7 +26,7 @@ public partial class SerializedModuleDefinition : ModuleDefinition /// /// The image to interpret as a .NET module. /// The parameters to use while reading the module. - public SerializedModuleDefinition(IPEImage peImage, ModuleReaderParameters readerParameters) + public SerializedModuleDefinition(PEImage peImage, ModuleReaderParameters readerParameters) : base(new MetadataToken(TableIndex.Module, 1)) { if (peImage is null) diff --git a/src/AsmResolver.PE/Builder/IPEFileBuilder.cs b/src/AsmResolver.PE/Builder/IPEFileBuilder.cs index 05423c2c8..362f22035 100644 --- a/src/AsmResolver.PE/Builder/IPEFileBuilder.cs +++ b/src/AsmResolver.PE/Builder/IPEFileBuilder.cs @@ -12,6 +12,6 @@ public interface IPEFileBuilder /// /// The image to assemble. /// The assembled PE file. - PEFile CreateFile(IPEImage image); + PEFile CreateFile(PEImage image); } -} \ No newline at end of file +} diff --git a/src/AsmResolver.PE/Builder/ManagedPEFileBuilder.cs b/src/AsmResolver.PE/Builder/ManagedPEFileBuilder.cs index a156e6388..ca186158a 100644 --- a/src/AsmResolver.PE/Builder/ManagedPEFileBuilder.cs +++ b/src/AsmResolver.PE/Builder/ManagedPEFileBuilder.cs @@ -25,17 +25,17 @@ namespace AsmResolver.PE.Builder; /// is written as-is without any change or verification. /// /// -/// This class might modify the final imports directory (exposed by the property), -/// as well as the base relocations directory (exposed by the property). In +/// This class might modify the final imports directory (exposed by the property), +/// as well as the base relocations directory (exposed by the property). In /// particular, it might add or remove the entry to mscoree.dll!_CorExeMain or mscoree.dll!_CorDllMain, -/// depending on the machine type specified by the property. +/// depending on the machine type specified by the property. /// /// /// This class builds up at most four PE sections; .text, .sdata, .rsrc and .reloc, /// similar to what a normal .NET language compiler would emit. Almost everything is put into the .text section, /// including the import and debug directories. The win32 resources are put into .rsrc section, and this /// section will only be added if there is at least one entry in the root resource directory of the -/// property. Similarly, the .sdata section is only added if at least +/// property. Similarly, the .sdata section is only added if at least /// one unmanaged export is added to the PE image. Finally, the .reloc section is only added if at least /// one base relocation was put into the directory, or when the CLR bootstrapper requires one. /// @@ -267,7 +267,7 @@ out var entryPointSymbol } private static List CollectImportedModules( - IPEImage image, + PEImage image, bool requireClrEntryPoint, string clrEntryPointName, out ImportedSymbol? clrEntryPoint) diff --git a/src/AsmResolver.PE/Builder/PEFileBuilder.cs b/src/AsmResolver.PE/Builder/PEFileBuilder.cs index 9fd62969f..0c9e97095 100644 --- a/src/AsmResolver.PE/Builder/PEFileBuilder.cs +++ b/src/AsmResolver.PE/Builder/PEFileBuilder.cs @@ -11,7 +11,7 @@ namespace AsmResolver.PE.Builder public abstract class PEFileBuilder : PEFileBuilder { /// - protected override PEFileBuilderContext CreateContext(IPEImage image) => new(image); + protected override PEFileBuilderContext CreateContext(PEImage image) => new(image); } /// @@ -22,7 +22,7 @@ public abstract class PEFileBuilder : IPEFileBuilder where TContext : PEFileBuilderContext { /// - public virtual PEFile CreateFile(IPEImage image) + public virtual PEFile CreateFile(PEImage image) { var peFile = new PEFile(); var context = CreateContext(image); @@ -42,7 +42,7 @@ public virtual PEFile CreateFile(IPEImage image) /// /// The image to build. /// The context. - protected abstract TContext CreateContext(IPEImage image); + protected abstract TContext CreateContext(PEImage image); /// /// Creates the sections of the PE image. diff --git a/src/AsmResolver.PE/Builder/PEFileBuilderContext.cs b/src/AsmResolver.PE/Builder/PEFileBuilderContext.cs index 025844de0..cdd4d0189 100644 --- a/src/AsmResolver.PE/Builder/PEFileBuilderContext.cs +++ b/src/AsmResolver.PE/Builder/PEFileBuilderContext.cs @@ -18,7 +18,7 @@ public class PEFileBuilderContext /// Creates a new PE file builder context. /// /// The image to build. - public PEFileBuilderContext(IPEImage image) + public PEFileBuilderContext(PEImage image) { Image = image; Platform = Platform.Get(image.MachineType); @@ -38,7 +38,7 @@ public PEFileBuilderContext(IPEImage image) /// /// Gets the input PE image to construct a file for. /// - public IPEImage Image + public PEImage Image { get; } diff --git a/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs b/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs index 1825e4ca4..8197c2610 100644 --- a/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs +++ b/src/AsmResolver.PE/Builder/UnmanagedPEFileBuilder.cs @@ -22,8 +22,8 @@ namespace AsmResolver.PE.Builder; /// directories or sometimes entire PE sections that are no longer in use. /// /// -/// This class might modify the final imports directory (exposed by the property), -/// as well as the base relocations directory (exposed by the property). In +/// This class might modify the final imports directory (exposed by the property), +/// as well as the base relocations directory (exposed by the property). In /// particular, it might add or remove the entry to mscoree.dll!_CorExeMain or mscoree.dll!_CorDllMain, /// and it may also add a reference to kernel32.dll!VirtualProtect in case dynamic initializers need to be /// injected to initialize reconstructed some parts of the original import address tables (IATs). @@ -124,7 +124,7 @@ public IImportedSymbolClassifier ImportedSymbolClassifier } = DefaultSymbolClassifier; /// - protected override BuilderContext CreateContext(IPEImage image) + protected override BuilderContext CreateContext(PEImage image) { var baseFile = BaseFile ?? image.PEFile; var baseImage = baseFile is not null @@ -768,7 +768,7 @@ public class BuilderContext : PEFileBuilderContext /// /// The image to build a PE file for. /// The template image to base the file on. - public BuilderContext(IPEImage image, IPEImage? baseImage) + public BuilderContext(PEImage image, PEImage? baseImage) : base(image) { BaseImage = baseImage; @@ -791,7 +791,7 @@ public BuilderContext(IPEImage image, IPEImage? baseImage) /// /// Gets the template image to base the file on. /// - public IPEImage? BaseImage { get; } + public PEImage? BaseImage { get; } /// /// Gets the trampolines table for all imported symbols. diff --git a/src/AsmResolver.PE/DotNet/Metadata/Tables/TypeReferenceHash.cs b/src/AsmResolver.PE/DotNet/Metadata/Tables/TypeReferenceHash.cs index 45da3d069..17e94440c 100644 --- a/src/AsmResolver.PE/DotNet/Metadata/Tables/TypeReferenceHash.cs +++ b/src/AsmResolver.PE/DotNet/Metadata/Tables/TypeReferenceHash.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using System.Security.Cryptography; -using AsmResolver.PE.DotNet.Metadata; namespace AsmResolver.PE.DotNet.Metadata.Tables { @@ -22,7 +21,7 @@ public static class TypeReferenceHash /// The image to get the TRH from. /// The hash. /// Occurs when the provided image does not contain .NET metadata. - public static byte[] GetTypeReferenceHash(this IPEImage image) + public static byte[] GetTypeReferenceHash(this PEImage image) { var metadata = image.DotNetDirectory?.Metadata; if (metadata is null) @@ -40,7 +39,7 @@ public static byte[] GetTypeReferenceHash(this IPEImage image) /// Occurs when the provided image does not contain .NET metadata. public static byte[] GetTypeReferenceHash(this IMetadata metadata) { - var tablesStream = metadata.GetStream(); + var tablesStream = metadata.GetStream(); var stringsStream = metadata.GetStream(); var table = tablesStream.GetTable(TableIndex.TypeRef); diff --git a/src/AsmResolver.PE/DotNet/StrongName/StrongNameSigner.cs b/src/AsmResolver.PE/DotNet/StrongName/StrongNameSigner.cs index 977d37643..4628d611f 100644 --- a/src/AsmResolver.PE/DotNet/StrongName/StrongNameSigner.cs +++ b/src/AsmResolver.PE/DotNet/StrongName/StrongNameSigner.cs @@ -74,7 +74,7 @@ public void SignImage(Stream imageStream, AssemblyHashAlgorithm hashAlgorithm) private byte[] GetHashToSign( Stream imageStream, PEFile file, - IPEImage image, + PEImage image, AssemblyHashAlgorithm hashAlgorithm) { var hashBuilder = new StrongNameDataHashBuilder(imageStream, hashAlgorithm); diff --git a/src/AsmResolver.PE/IPEImage.cs b/src/AsmResolver.PE/IPEImage.cs deleted file mode 100644 index 01951b655..000000000 --- a/src/AsmResolver.PE/IPEImage.cs +++ /dev/null @@ -1,218 +0,0 @@ -using System; -using System.Collections.Generic; -using AsmResolver.PE.Builder; -using AsmResolver.PE.Certificates; -using AsmResolver.PE.Debug; -using AsmResolver.PE.DotNet; -using AsmResolver.PE.Exceptions; -using AsmResolver.PE.Exports; -using AsmResolver.PE.File; -using AsmResolver.PE.Imports; -using AsmResolver.PE.Relocations; -using AsmResolver.PE.Tls; -using AsmResolver.PE.Win32Resources; - -namespace AsmResolver.PE -{ - /// - /// Represents an image of a portable executable (PE) file, exposing high level mutable structures. - /// - public interface IPEImage - { - /// - /// Gets the underlying PE file (when available). - /// - /// - /// When this property is null, the image is a new image that is not yet assembled. - /// - /// Accessing and using this object file is considered an unsafe operation. Making any changes to this object - /// while also using the PE image object can have unwanted side effects. - /// - /// - PEFile? PEFile - { - get; - } - - /// - /// When this PE image was read from the disk, gets the file path to the PE image. - /// - string? FilePath - { - get; - } - - /// - /// Gets or sets the machine type that the PE image is targeting. - /// - /// - /// This property is in direct relation with the machine type field in the file header of a portable - /// executable file. - /// - MachineType MachineType - { - get; - set; - } - - /// - /// Gets or sets the attributes assigned to the executable file. - /// - /// - /// This property is in direct relation with the characteristics field in the file header of a portable - /// executable file. - /// - Characteristics Characteristics - { - get; - set; - } - - /// - /// Gets or sets the date and time the portable executable file was created. - /// - DateTime TimeDateStamp - { - get; - set; - } - - /// - /// Gets or sets the magic optional header signature, determining whether the image is a PE32 (32-bit) or a - /// PE32+ (64-bit) image. - /// - /// - /// This property is in direct relation with the magic field in the optional header of a portable - /// executable file. - /// - OptionalHeaderMagic PEKind - { - get; - set; - } - - /// - /// Gets or sets the subsystem to use when running the portable executable (PE) file. - /// - /// - /// This property is in direct relation with the subsystem field in the optional header of a portable - /// executable file. - /// - SubSystem SubSystem - { - get; - set; - } - - /// - /// Gets or sets the dynamic linked library characteristics of the portable executable (PE) file. - /// - /// - /// This property is in direct relation with the DLL characteristics field in the optional header of a portable - /// executable file. - /// - DllCharacteristics DllCharacteristics - { - get; - set; - } - - /// - /// Gets or sets the preferred address of the first byte of the image when loaded into memory. Must be a - /// multiple of 64,000. - /// - /// - /// This property is in direct relation with the image base field in the optional header of a portable - /// executable file. - /// - ulong ImageBase - { - get; - set; - } - - /// - /// Gets a collection of modules that were imported into the PE, according to the import data directory. - /// - IList Imports - { - get; - } - - /// - /// Gets or sets the exports directory in the PE, if available. - /// - IExportDirectory? Exports - { - get; - set; - } - - /// - /// Gets or sets the root resource directory in the PE, if available. - /// - IResourceDirectory? Resources - { - get; - set; - } - - /// - /// Gets or sets the exceptions directory in the PE, if available. - /// - IExceptionDirectory? Exceptions - { - get; - set; - } - - /// - /// Gets a collection of base relocations that are to be applied when loading the PE into memory for execution. - /// - IList Relocations - { - get; - } - - /// - /// Gets or sets the data directory containing the CLR 2.0 header of a .NET binary (if available). - /// - IDotNetDirectory? DotNetDirectory - { - get; - set; - } - - /// - /// Gets a collection of data entries stored in the debug data directory of the PE image (if available). - /// - IList DebugData - { - get; - } - - /// - /// Gets or sets the data directory containing the Thread-Local Storage (TLS) data. - /// - ITlsDirectory? TlsDirectory - { - get; - set; - } - - /// - /// Gets a collection of attribute certificates that were added to the executable. - /// - CertificateCollection Certificates - { - get; - } - - /// - /// Constructs a PE file from the image. - /// - /// The builder to use for constructing the image. - /// The constructed file. - PEFile ToPEFile(IPEFileBuilder builder); - } -} diff --git a/src/AsmResolver.PE/Imports/ImportHash.cs b/src/AsmResolver.PE/Imports/ImportHash.cs index a3c522ed8..081cb93ec 100644 --- a/src/AsmResolver.PE/Imports/ImportHash.cs +++ b/src/AsmResolver.PE/Imports/ImportHash.cs @@ -25,7 +25,7 @@ public static class ImportHash /// This is the ImpHash as introduced by Mandiant. /// Reference: https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html /// - public static byte[] GetImportHash(this IPEImage image) => image.GetImportHash(DefaultSymbolResolver.Instance); + public static byte[] GetImportHash(this PEImage image) => image.GetImportHash(DefaultSymbolResolver.Instance); /// /// Computes the hash of all imported symbols. @@ -37,7 +37,7 @@ public static class ImportHash /// This is the ImpHash as introduced by Mandiant. /// Reference: https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html /// - public static byte[] GetImportHash(this IPEImage image, ISymbolResolver symbolResolver) + public static byte[] GetImportHash(this PEImage image, ISymbolResolver symbolResolver) { var elements = new List(); diff --git a/src/AsmResolver.PE/PEImage.cs b/src/AsmResolver.PE/PEImage.cs index 3cec90ead..ccc2720e9 100644 --- a/src/AsmResolver.PE/PEImage.cs +++ b/src/AsmResolver.PE/PEImage.cs @@ -17,9 +17,9 @@ namespace AsmResolver.PE { /// - /// Provides an implementation for a portable executable (PE) image. + /// Represents an image of a portable executable (PE) file, exposing high level mutable structures. /// - public class PEImage : IPEImage + public class PEImage { private IList? _imports; private readonly LazyVariable _exports; @@ -37,7 +37,7 @@ public class PEImage : IPEImage /// The /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromFile(string filePath) => FromFile(PEFile.FromFile(filePath)); + public static PEImage FromFile(string filePath) => FromFile(PEFile.FromFile(filePath)); /// /// Opens a PE image from a specific file on the disk. @@ -46,7 +46,7 @@ public class PEImage : IPEImage /// The parameters to use while reading the PE image. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromFile(string filePath, PEReaderParameters readerParameters) => + public static PEImage FromFile(string filePath, PEReaderParameters readerParameters) => FromFile(PEFile.FromFile(readerParameters.FileService.OpenFile(filePath)), readerParameters); /// @@ -55,7 +55,7 @@ public static IPEImage FromFile(string filePath, PEReaderParameters readerParame /// The bytes to interpret. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromBytes(byte[] bytes) => FromFile(PEFile.FromBytes(bytes)); + public static PEImage FromBytes(byte[] bytes) => FromFile(PEFile.FromBytes(bytes)); /// /// Opens a PE image from a buffer. @@ -64,7 +64,7 @@ public static IPEImage FromFile(string filePath, PEReaderParameters readerParame /// The parameters to use while reading the PE image. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromBytes(byte[] bytes, PEReaderParameters readerParameters) => + public static PEImage FromBytes(byte[] bytes, PEReaderParameters readerParameters) => FromFile(PEFile.FromBytes(bytes), readerParameters); /// @@ -73,7 +73,7 @@ public static IPEImage FromBytes(byte[] bytes, PEReaderParameters readerParamete /// The HINSTANCE or base address of the module. /// The PE image that was read. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromModuleBaseAddress(IntPtr hInstance) => + public static PEImage FromModuleBaseAddress(IntPtr hInstance) => FromModuleBaseAddress(hInstance, PEMappingMode.Mapped, new PEReaderParameters()); /// @@ -83,7 +83,7 @@ public static IPEImage FromModuleBaseAddress(IntPtr hInstance) => /// The parameters to use while reading the PE image. /// The PE image that was read. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromModuleBaseAddress(IntPtr hInstance, PEReaderParameters readerParameters) => + public static PEImage FromModuleBaseAddress(IntPtr hInstance, PEReaderParameters readerParameters) => FromFile(PEFile.FromModuleBaseAddress(hInstance), readerParameters); /// @@ -94,7 +94,7 @@ public static IPEImage FromModuleBaseAddress(IntPtr hInstance, PEReaderParameter /// The parameters to use while reading the PE image. /// The PE image that was read. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromModuleBaseAddress(IntPtr hInstance, PEMappingMode mode, PEReaderParameters readerParameters) => + public static PEImage FromModuleBaseAddress(IntPtr hInstance, PEMappingMode mode, PEReaderParameters readerParameters) => FromFile(PEFile.FromModuleBaseAddress(hInstance, mode), readerParameters); /// @@ -104,7 +104,7 @@ public static IPEImage FromModuleBaseAddress(IntPtr hInstance, PEMappingMode mod /// Indicates how the input PE file is mapped. /// The PE image that was read. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromDataSource(IDataSource dataSource, PEMappingMode mode = PEMappingMode.Unmapped) => + public static PEImage FromDataSource(IDataSource dataSource, PEMappingMode mode = PEMappingMode.Unmapped) => FromReader(new BinaryStreamReader(dataSource, dataSource.BaseAddress, 0, (uint) dataSource.Length), mode); /// @@ -115,7 +115,7 @@ public static IPEImage FromDataSource(IDataSource dataSource, PEMappingMode mode /// The parameters to use while reading the PE image. /// The PE image that was read. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromDataSource(IDataSource dataSource, PEMappingMode mode, PEReaderParameters readerParameters) => + public static PEImage FromDataSource(IDataSource dataSource, PEMappingMode mode, PEReaderParameters readerParameters) => FromReader(new BinaryStreamReader(dataSource, dataSource.BaseAddress, 0, (uint) dataSource.Length), mode, readerParameters); /// @@ -125,7 +125,7 @@ public static IPEImage FromDataSource(IDataSource dataSource, PEMappingMode mode /// Indicates the input PE is in its mapped or unmapped form. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromReader(in BinaryStreamReader reader, PEMappingMode mode = PEMappingMode.Unmapped) => + public static PEImage FromReader(in BinaryStreamReader reader, PEMappingMode mode = PEMappingMode.Unmapped) => FromFile(PEFile.FromReader(reader, mode)); /// @@ -136,7 +136,7 @@ public static IPEImage FromReader(in BinaryStreamReader reader, PEMappingMode mo /// The parameters to use while reading the PE image. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromReader(in BinaryStreamReader reader, PEMappingMode mode, PEReaderParameters readerParameters) => + public static PEImage FromReader(in BinaryStreamReader reader, PEMappingMode mode, PEReaderParameters readerParameters) => FromFile(PEFile.FromReader(reader, mode), readerParameters); /// @@ -145,7 +145,7 @@ public static IPEImage FromReader(in BinaryStreamReader reader, PEMappingMode mo /// The file representing the PE. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromFile(IInputFile inputFile) => FromFile(inputFile, new PEReaderParameters()); + public static PEImage FromFile(IInputFile inputFile) => FromFile(inputFile, new PEReaderParameters()); /// /// Opens a PE image from an input file object. @@ -154,7 +154,7 @@ public static IPEImage FromReader(in BinaryStreamReader reader, PEMappingMode mo /// The parameters to use while reading the PE image. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromFile(IInputFile inputFile, PEReaderParameters readerParameters) => + public static PEImage FromFile(IInputFile inputFile, PEReaderParameters readerParameters) => FromFile(PEFile.FromFile(inputFile), readerParameters); /// @@ -163,7 +163,7 @@ public static IPEImage FromFile(IInputFile inputFile, PEReaderParameters readerP /// The PE file object. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromFile(PEFile peFile) => FromFile(peFile, new PEReaderParameters()); + public static PEImage FromFile(PEFile peFile) => FromFile(peFile, new PEReaderParameters()); /// /// Opens a PE image from a PE file object. @@ -172,7 +172,7 @@ public static IPEImage FromFile(IInputFile inputFile, PEReaderParameters readerP /// The parameters to use while reading the PE image. /// The PE image that was opened. /// Occurs when the file does not follow the PE file format. - public static IPEImage FromFile(PEFile peFile, PEReaderParameters readerParameters) => + public static PEImage FromFile(PEFile peFile, PEReaderParameters readerParameters) => new SerializedPEImage(peFile, readerParameters); /// @@ -187,52 +187,96 @@ public PEImage() _tlsDirectory = new LazyVariable(x => x.GetTlsDirectory()); } - /// + /// + /// Gets the underlying PE file (when available). + /// + /// + /// When this property is null, the image is a new image that is not yet assembled. + /// + /// Accessing and using this object file is considered an unsafe operation. Making any changes to this object + /// while also using the PE image object can have unwanted side effects. + /// + /// public virtual PEFile? PEFile => null; - /// + /// + /// When this PE image was read from the disk, gets the file path to the PE image. + /// public string? FilePath { get; protected set; } - /// + /// + /// Gets or sets the machine type that the PE image is targeting. + /// + /// + /// This property is in direct relation with the machine type field in the file header of a portable + /// executable file. + /// public MachineType MachineType { get; set; } = MachineType.I386; - /// + /// + /// Gets or sets the attributes assigned to the executable file. + /// + /// + /// This property is in direct relation with the characteristics field in the file header of a portable + /// executable file. + /// public Characteristics Characteristics { get; set; } = Characteristics.Image | Characteristics.LargeAddressAware; - /// + /// + /// Gets or sets the date and time the portable executable file was created. + /// public DateTime TimeDateStamp { get; set; - } = new DateTime(1970, 1, 1); + } = new(1970, 1, 1); - /// + /// + /// Gets or sets the magic optional header signature, determining whether the image is a PE32 (32-bit) or a + /// PE32+ (64-bit) image. + /// + /// + /// This property is in direct relation with the magic field in the optional header of a portable + /// executable file. + /// public OptionalHeaderMagic PEKind { get; set; } = OptionalHeaderMagic.PE32; - /// + /// + /// Gets or sets the subsystem to use when running the portable executable (PE) file. + /// + /// + /// This property is in direct relation with the subsystem field in the optional header of a portable + /// executable file. + /// public SubSystem SubSystem { get; set; } = SubSystem.WindowsCui; - /// + /// + /// Gets or sets the dynamic linked library characteristics of the portable executable (PE) file. + /// + /// + /// This property is in direct relation with the DLL characteristics field in the optional header of a portable + /// executable file. + /// public DllCharacteristics DllCharacteristics { get; @@ -240,14 +284,23 @@ public DllCharacteristics DllCharacteristics } = DllCharacteristics.DynamicBase | DllCharacteristics.NoSeh | DllCharacteristics.NxCompat | DllCharacteristics.TerminalServerAware; - /// + /// + /// Gets or sets the preferred address of the first byte of the image when loaded into memory. Must be a + /// multiple of 64,000. + /// + /// + /// This property is in direct relation with the image base field in the optional header of a portable + /// executable file. + /// public ulong ImageBase { get; set; } = 0x00400000; - /// + /// + /// Gets a collection of modules that were imported into the PE, according to the import data directory. + /// public IList Imports { get @@ -258,28 +311,36 @@ public IList Imports } } - /// + /// + /// Gets or sets the exports directory in the PE, if available. + /// public IExportDirectory? Exports { get => _exports.GetValue(this); set => _exports.SetValue(value); } - /// + /// + /// Gets or sets the root resource directory in the PE, if available. + /// public IResourceDirectory? Resources { get => _resources.GetValue(this); set => _resources.SetValue(value); } - /// + /// + /// Gets or sets the exceptions directory in the PE, if available. + /// public IExceptionDirectory? Exceptions { get => _exceptions.GetValue(this); set => _exceptions.SetValue(value); } - /// + /// + /// Gets a collection of base relocations that are to be applied when loading the PE into memory for execution. + /// public IList Relocations { get @@ -290,14 +351,18 @@ public IList Relocations } } - /// + /// + /// Gets or sets the data directory containing the CLR 2.0 header of a .NET binary (if available). + /// public IDotNetDirectory? DotNetDirectory { get => _dotNetDirectory.GetValue(this); set => _dotNetDirectory.SetValue(value); } - /// + /// + /// Gets a collection of data entries stored in the debug data directory of the PE image (if available). + /// public IList DebugData { get @@ -308,14 +373,18 @@ public IList DebugData } } - /// + /// + /// Gets or sets the data directory containing the Thread-Local Storage (TLS) data. + /// public ITlsDirectory? TlsDirectory { get => _tlsDirectory.GetValue(this); set => _tlsDirectory.SetValue(value); } - /// + /// + /// Gets a collection of attribute certificates that were added to the executable. + /// public CertificateCollection Certificates { get @@ -326,7 +395,11 @@ public CertificateCollection Certificates } } - /// + /// + /// Constructs a PE file from the image. + /// + /// The builder to use for constructing the image. + /// The constructed file. public PEFile ToPEFile(IPEFileBuilder builder) => builder.CreateFile(this); /// diff --git a/src/AsmResolver.PE/Platforms/Amd64Platform.cs b/src/AsmResolver.PE/Platforms/Amd64Platform.cs index 08d28c074..2771e0181 100644 --- a/src/AsmResolver.PE/Platforms/Amd64Platform.cs +++ b/src/AsmResolver.PE/Platforms/Amd64Platform.cs @@ -45,7 +45,7 @@ public override RelocatableSegment CreateThunkStub(ISymbol entryPoint) } /// - public override bool TryExtractThunkAddress(IPEImage image, BinaryStreamReader reader, out uint rva) + public override bool TryExtractThunkAddress(PEImage image, BinaryStreamReader reader, out uint rva) { if (reader.ReadUInt16() != 0xA148) { diff --git a/src/AsmResolver.PE/Platforms/I386Platform.cs b/src/AsmResolver.PE/Platforms/I386Platform.cs index 8f34560ac..5c7bfe675 100644 --- a/src/AsmResolver.PE/Platforms/I386Platform.cs +++ b/src/AsmResolver.PE/Platforms/I386Platform.cs @@ -44,7 +44,7 @@ public override RelocatableSegment CreateThunkStub(ISymbol entryPoint) } /// - public override bool TryExtractThunkAddress(IPEImage image, BinaryStreamReader reader, out uint rva) + public override bool TryExtractThunkAddress(PEImage image, BinaryStreamReader reader, out uint rva) { if (reader.ReadUInt16() != 0x25FF) { diff --git a/src/AsmResolver.PE/Platforms/Platform.cs b/src/AsmResolver.PE/Platforms/Platform.cs index bb3f583a6..95aba58cf 100644 --- a/src/AsmResolver.PE/Platforms/Platform.cs +++ b/src/AsmResolver.PE/Platforms/Platform.cs @@ -97,7 +97,7 @@ public abstract bool Is32Bit /// The thunk reader. /// The extracted RVA. /// true if the RVA was extracted successfully from the code, false otherwise. - public abstract bool TryExtractThunkAddress(IPEImage image, BinaryStreamReader reader, out uint rva); + public abstract bool TryExtractThunkAddress(PEImage image, BinaryStreamReader reader, out uint rva); /// /// Creates a new address table initializer stub. diff --git a/test/AsmResolver.DotNet.Tests/Code/Native/NativeMethodBodyTest.cs b/test/AsmResolver.DotNet.Tests/Code/Native/NativeMethodBodyTest.cs index 5ef7f8759..a947d0306 100644 --- a/test/AsmResolver.DotNet.Tests/Code/Native/NativeMethodBodyTest.cs +++ b/test/AsmResolver.DotNet.Tests/Code/Native/NativeMethodBodyTest.cs @@ -60,7 +60,7 @@ private static NativeMethodBody CreateDummyBody(bool isVoid, bool is32Bit) return method.NativeMethodBody = new NativeMethodBody(method); } - private static IReadableSegment GetNewCodeSegment(IPEImage image) + private static IReadableSegment GetNewCodeSegment(PEImage image) { var methodTable = image.DotNetDirectory!.Metadata! .GetStream() diff --git a/test/AsmResolver.PE.Tests/Builder/MixedModeAssemblyTest.cs b/test/AsmResolver.PE.Tests/Builder/MixedModeAssemblyTest.cs index 3fb2f0d1b..5354d41d0 100644 --- a/test/AsmResolver.PE.Tests/Builder/MixedModeAssemblyTest.cs +++ b/test/AsmResolver.PE.Tests/Builder/MixedModeAssemblyTest.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.InteropServices; using AsmResolver.PE.Builder; using AsmResolver.PE.Code; using AsmResolver.PE.DotNet; @@ -24,7 +23,7 @@ public MixedModeAssemblyTest(TemporaryDirectoryFixture fixture) _fixture = fixture; } - private static void ReplaceBodyWithNativeCode(IPEImage image, ISegment body, bool is32bit) + private static void ReplaceBodyWithNativeCode(PEImage image, ISegment body, bool is32bit) { // Adjust image flags appropriately. image.DotNetDirectory!.Flags &= ~DotNetDirectoryFlags.ILOnly; diff --git a/test/AsmResolver.PE.Tests/Debug/DebugDataEntryTest.cs b/test/AsmResolver.PE.Tests/Debug/DebugDataEntryTest.cs index 2b15f9daa..1a7215bba 100644 --- a/test/AsmResolver.PE.Tests/Debug/DebugDataEntryTest.cs +++ b/test/AsmResolver.PE.Tests/Debug/DebugDataEntryTest.cs @@ -9,7 +9,7 @@ namespace AsmResolver.PE.Tests.Debug { public class DebugDataEntryTest { - private static IPEImage RebuildAndReloadManagedPE(IPEImage image) + private static PEImage RebuildAndReloadManagedPE(PEImage image) { // Build. using var tempStream = new MemoryStream(); diff --git a/test/AsmResolver.PE.Tests/DotNet/Metadata/MetadataTest.cs b/test/AsmResolver.PE.Tests/DotNet/Metadata/MetadataTest.cs index b5724e8aa..febac51f4 100644 --- a/test/AsmResolver.PE.Tests/DotNet/Metadata/MetadataTest.cs +++ b/test/AsmResolver.PE.Tests/DotNet/Metadata/MetadataTest.cs @@ -138,7 +138,7 @@ private void AssertCorrectStreamIsSelected(byte[] assembly, bool isEnC) AssertCorrectStreamIsSelected(PEImage.FromBytes(assembly), isEnC); } - private void AssertCorrectStreamIsSelected(IPEImage peImage, bool isEnC) + private void AssertCorrectStreamIsSelected(PEImage peImage, bool isEnC) where TStream : class, IMetadataStream { var metadata = peImage.DotNetDirectory!.Metadata!; diff --git a/test/AsmResolver.PE.Tests/DotNet/ReadyToRun/ReadyToRunDirectoryTest.cs b/test/AsmResolver.PE.Tests/DotNet/ReadyToRun/ReadyToRunDirectoryTest.cs index 4f0bc2327..af835b93c 100644 --- a/test/AsmResolver.PE.Tests/DotNet/ReadyToRun/ReadyToRunDirectoryTest.cs +++ b/test/AsmResolver.PE.Tests/DotNet/ReadyToRun/ReadyToRunDirectoryTest.cs @@ -8,7 +8,7 @@ namespace AsmResolver.PE.Tests.DotNet.ReadyToRun { public class ReadyToRunDirectoryTest { - private static T GetSection(IPEImage image, bool rebuild) + private static T GetSection(PEImage image, bool rebuild) where T : class, IReadyToRunSection { var serializedImage = (SerializedPEImage) image; diff --git a/test/AsmResolver.PE.Tests/DotNet/VTableFixups/VTableFixupsDirectoryTest.cs b/test/AsmResolver.PE.Tests/DotNet/VTableFixups/VTableFixupsDirectoryTest.cs index 66c2ab3ff..00ee3ee3f 100644 --- a/test/AsmResolver.PE.Tests/DotNet/VTableFixups/VTableFixupsDirectoryTest.cs +++ b/test/AsmResolver.PE.Tests/DotNet/VTableFixups/VTableFixupsDirectoryTest.cs @@ -8,7 +8,7 @@ namespace AsmResolver.PE.Tests.DotNet.VTableFixups { public class VTableFixupsDirectoryTest { - private static IPEImage RebuildAndReloadManagedPE(IPEImage image) + private static PEImage RebuildAndReloadManagedPE(PEImage image) { // Build. using var tempStream = new MemoryStream(); diff --git a/test/AsmResolver.PE.Tests/Exports/ExportDirectoryTest.cs b/test/AsmResolver.PE.Tests/Exports/ExportDirectoryTest.cs index 0143ddc0f..6a50a3dca 100644 --- a/test/AsmResolver.PE.Tests/Exports/ExportDirectoryTest.cs +++ b/test/AsmResolver.PE.Tests/Exports/ExportDirectoryTest.cs @@ -97,7 +97,7 @@ public void InsertExportShouldUpdateOrdinals() }, image.Exports.Entries.Select(e => e.Ordinal)); } - private static IPEImage RebuildAndReloadManagedPE(IPEImage image) + private static PEImage RebuildAndReloadManagedPE(PEImage image) { // Build. using var tempStream = new MemoryStream(); From 6c3f5538ff2ef96e5311d65894b0e9a3713693ae Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 3 Jun 2024 23:46:34 +0200 Subject: [PATCH 3/8] Remove IDotNetDirectory and IMetadata. --- .../Builder/DotNetDirectoryBuildResult.cs | 6 +- .../Builder/DotNetDirectoryFactory.cs | 2 +- .../Builder/IDotNetDirectoryFactory.cs | 2 +- .../Builder/Metadata/IMetadataBuffer.cs | 2 +- .../Builder/Metadata/MetadataBuffer.cs | 8 +- .../Builder/PEImageBuildResult.cs | 2 +- .../Collections/LazyRidListRelation.cs | 4 +- src/AsmResolver.DotNet/ModuleDefinition.cs | 2 +- .../Serialized/ModuleReaderContext.cs | 2 +- .../Serialized/ModuleReaderParameters.cs | 2 +- .../Serialized/SerializedModuleDefinition.cs | 2 +- src/AsmResolver.DotNet/TokenAllocator.cs | 4 +- src/AsmResolver.PE/DotNet/DotNetDirectory.cs | 70 +++++++--- src/AsmResolver.PE/DotNet/IDotNetDirectory.cs | 125 ------------------ .../DotNet/Metadata/FieldRvaDataReader.cs | 8 +- .../DotNet/Metadata/IFieldRvaDataReader.cs | 8 +- .../DotNet/Metadata/ILazyMetadataStream.cs | 2 +- .../DotNet/Metadata/IMetadata.cs | 113 ---------------- .../{Metadata.cs => MetadataDirectory.cs} | 79 ++++++++--- .../DotNet/Metadata/MetadataStreamList.cs | 4 +- ...data.cs => SerializedMetadataDirectory.cs} | 4 +- .../DotNet/Metadata/SerializedTableStream.cs | 2 +- .../Metadata/Tables/TypeReferenceHash.cs | 2 +- .../DotNet/SerializedDotNetDirectory.cs | 4 +- src/AsmResolver.PE/PEImage.cs | 8 +- src/AsmResolver.PE/SerializedPEImage.cs | 2 +- ...tadataTest.cs => MetadataDirectoryTest.cs} | 4 +- .../DotNet/Metadata/PdbStreamTest.cs | 6 +- .../Metadata/Tables/TablesStreamTest.cs | 12 +- .../Resources/DotNetResourcesDirectoryTest.cs | 2 +- 30 files changed, 168 insertions(+), 325 deletions(-) delete mode 100644 src/AsmResolver.PE/DotNet/IDotNetDirectory.cs delete mode 100644 src/AsmResolver.PE/DotNet/Metadata/IMetadata.cs rename src/AsmResolver.PE/DotNet/Metadata/{Metadata.cs => MetadataDirectory.cs} (74%) rename src/AsmResolver.PE/DotNet/Metadata/{SerializedMetadata.cs => SerializedMetadataDirectory.cs} (96%) rename test/AsmResolver.PE.Tests/DotNet/Metadata/{MetadataTest.cs => MetadataDirectoryTest.cs} (98%) diff --git a/src/AsmResolver.DotNet/Builder/DotNetDirectoryBuildResult.cs b/src/AsmResolver.DotNet/Builder/DotNetDirectoryBuildResult.cs index ee7e362b8..61fa09c9e 100644 --- a/src/AsmResolver.DotNet/Builder/DotNetDirectoryBuildResult.cs +++ b/src/AsmResolver.DotNet/Builder/DotNetDirectoryBuildResult.cs @@ -4,7 +4,7 @@ namespace AsmResolver.DotNet.Builder { /// - /// Describes the result of a construction of a . from a . + /// Describes the result of a construction of a . from a . /// public class DotNetDirectoryBuildResult { @@ -13,7 +13,7 @@ public class DotNetDirectoryBuildResult /// /// The constructed directory. /// An object defining a mapping between members and their new metadata tokens. - public DotNetDirectoryBuildResult(IDotNetDirectory directory, ITokenMapping mapping) + public DotNetDirectoryBuildResult(DotNetDirectory directory, ITokenMapping mapping) { Directory = directory ?? throw new ArgumentNullException(nameof(directory)); TokenMapping = mapping ?? throw new ArgumentNullException(nameof(mapping)); @@ -22,7 +22,7 @@ public DotNetDirectoryBuildResult(IDotNetDirectory directory, ITokenMapping mapp /// /// Gets the constructed .NET data directory. /// - public IDotNetDirectory Directory + public DotNetDirectory Directory { get; } diff --git a/src/AsmResolver.DotNet/Builder/DotNetDirectoryFactory.cs b/src/AsmResolver.DotNet/Builder/DotNetDirectoryFactory.cs index 7c9eeaca4..0d164845e 100644 --- a/src/AsmResolver.DotNet/Builder/DotNetDirectoryFactory.cs +++ b/src/AsmResolver.DotNet/Builder/DotNetDirectoryFactory.cs @@ -299,7 +299,7 @@ private static void ImportTables(ModuleDefinition module, TableIndex ta importAction((TMember) member); } - private void ReorderMetadataStreams(SerializedModuleDefinition serializedModule, IMetadata newMetadata) + private void ReorderMetadataStreams(SerializedModuleDefinition serializedModule, MetadataDirectory newMetadata) { IMetadataStream? GetStreamOrNull() where TStream : class, IMetadataStream diff --git a/src/AsmResolver.DotNet/Builder/IDotNetDirectoryFactory.cs b/src/AsmResolver.DotNet/Builder/IDotNetDirectoryFactory.cs index 97ba5fd96..bfa858c27 100644 --- a/src/AsmResolver.DotNet/Builder/IDotNetDirectoryFactory.cs +++ b/src/AsmResolver.DotNet/Builder/IDotNetDirectoryFactory.cs @@ -4,7 +4,7 @@ namespace AsmResolver.DotNet.Builder { /// - /// Provides members for constructing a .NET data directory that can be inserted into a . + /// Provides members for constructing a .NET data directory that can be inserted into a . /// public interface IDotNetDirectoryFactory { diff --git a/src/AsmResolver.DotNet/Builder/Metadata/IMetadataBuffer.cs b/src/AsmResolver.DotNet/Builder/Metadata/IMetadataBuffer.cs index 067c41c2e..b0a8ce483 100644 --- a/src/AsmResolver.DotNet/Builder/Metadata/IMetadataBuffer.cs +++ b/src/AsmResolver.DotNet/Builder/Metadata/IMetadataBuffer.cs @@ -52,6 +52,6 @@ TablesStreamBuffer TablesStream /// Flushes all metadata stream buffers and builds up a new metadata directory. /// /// The constructed metadata directory. - IMetadata CreateMetadata(); + MetadataDirectory CreateMetadata(); } } diff --git a/src/AsmResolver.DotNet/Builder/Metadata/MetadataBuffer.cs b/src/AsmResolver.DotNet/Builder/Metadata/MetadataBuffer.cs index 7d449edfc..a67f19a59 100644 --- a/src/AsmResolver.DotNet/Builder/Metadata/MetadataBuffer.cs +++ b/src/AsmResolver.DotNet/Builder/Metadata/MetadataBuffer.cs @@ -72,10 +72,10 @@ public bool OptimizeStringIndices } = true; /// - public IMetadata CreateMetadata() + public MetadataDirectory CreateMetadata() { // Create metadata directory. - var result = new PE.DotNet.Metadata.Metadata + var result = new MetadataDirectory { VersionString = _versionString, IsEncMetadata = TablesStream.IsEncMetadata @@ -101,7 +101,7 @@ public IMetadata CreateMetadata() return result; } - private static TStream? AddIfNotEmpty(IMetadata metadata, IMetadataStreamBuffer streamBuffer) + private static TStream? AddIfNotEmpty(MetadataDirectory metadata, IMetadataStreamBuffer streamBuffer) where TStream : class, IMetadataStream { return !streamBuffer.IsEmpty @@ -109,7 +109,7 @@ public IMetadata CreateMetadata() : null; } - private static TStream Add(IMetadata metadata, IMetadataStreamBuffer streamBuffer) + private static TStream Add(MetadataDirectory metadata, IMetadataStreamBuffer streamBuffer) where TStream : class, IMetadataStream { var stream = streamBuffer.CreateStream(); diff --git a/src/AsmResolver.DotNet/Builder/PEImageBuildResult.cs b/src/AsmResolver.DotNet/Builder/PEImageBuildResult.cs index cdc3cb65d..22599ad3d 100644 --- a/src/AsmResolver.DotNet/Builder/PEImageBuildResult.cs +++ b/src/AsmResolver.DotNet/Builder/PEImageBuildResult.cs @@ -5,7 +5,7 @@ namespace AsmResolver.DotNet.Builder { /// - /// Describes the result of the construction of a from a . + /// Describes the result of the construction of a from a . /// public class PEImageBuildResult { diff --git a/src/AsmResolver.DotNet/Collections/LazyRidListRelation.cs b/src/AsmResolver.DotNet/Collections/LazyRidListRelation.cs index 95130b8bf..0c345c1b9 100644 --- a/src/AsmResolver.DotNet/Collections/LazyRidListRelation.cs +++ b/src/AsmResolver.DotNet/Collections/LazyRidListRelation.cs @@ -12,7 +12,7 @@ internal class LazyRidListRelation public delegate uint GetOwnerRidDelegate(uint rid, TAssociationRow row); public delegate MetadataRange GetMemberListDelegate(uint rid); - private readonly IMetadata _metadata; + private readonly MetadataDirectory _metadata; private readonly TableIndex _associationTable; private readonly TableIndex _memberTable; private readonly GetOwnerRidDelegate _getOwnerRid; @@ -28,7 +28,7 @@ internal class LazyRidListRelation private uint[]? _memberOwnerRids; public LazyRidListRelation( - IMetadata metadata, + MetadataDirectory metadata, TableIndex memberTable, TableIndex associationTable, GetOwnerRidDelegate getOwnerRid, diff --git a/src/AsmResolver.DotNet/ModuleDefinition.cs b/src/AsmResolver.DotNet/ModuleDefinition.cs index b32628e7f..22cd72efd 100644 --- a/src/AsmResolver.DotNet/ModuleDefinition.cs +++ b/src/AsmResolver.DotNet/ModuleDefinition.cs @@ -343,7 +343,7 @@ public string? FilePath /// /// When this property is null, the module is a new module that is not yet assembled. /// - public virtual IDotNetDirectory? DotNetDirectory + public virtual DotNetDirectory? DotNetDirectory { get; } = null; diff --git a/src/AsmResolver.DotNet/Serialized/ModuleReaderContext.cs b/src/AsmResolver.DotNet/Serialized/ModuleReaderContext.cs index 669cfad8d..b2b7555d3 100644 --- a/src/AsmResolver.DotNet/Serialized/ModuleReaderContext.cs +++ b/src/AsmResolver.DotNet/Serialized/ModuleReaderContext.cs @@ -86,7 +86,7 @@ public SerializedModuleDefinition ParentModule /// /// Gets the original metadata directory. /// - public IMetadata Metadata => Image.DotNetDirectory!.Metadata!; + public MetadataDirectory Metadata => Image.DotNetDirectory!.Metadata!; /// /// Gets the main tables stream in the metadata directory. diff --git a/src/AsmResolver.DotNet/Serialized/ModuleReaderParameters.cs b/src/AsmResolver.DotNet/Serialized/ModuleReaderParameters.cs index 29a30dcc9..c92664671 100644 --- a/src/AsmResolver.DotNet/Serialized/ModuleReaderParameters.cs +++ b/src/AsmResolver.DotNet/Serialized/ModuleReaderParameters.cs @@ -137,7 +137,7 @@ public IFieldRvaDataReader FieldRvaDataReader /// Gets or sets the parameters used for parsing a PE file into a PE image. /// /// - /// This property is ignored when the module was read from a + /// This property is ignored when the module was read from a /// public PEReaderParameters PEReaderParameters { diff --git a/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs b/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs index f1f70dac1..e755a2234 100644 --- a/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs +++ b/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs @@ -114,7 +114,7 @@ public SerializedModuleDefinition(PEImage peImage, ModuleReaderParameters reader } /// - public override IDotNetDirectory DotNetDirectory => ReaderContext.Image.DotNetDirectory!; + public override DotNetDirectory DotNetDirectory => ReaderContext.Image.DotNetDirectory!; /// /// Gets the reading context that is used for reading the contents of the module. diff --git a/src/AsmResolver.DotNet/TokenAllocator.cs b/src/AsmResolver.DotNet/TokenAllocator.cs index 953a1399e..ac6d77ce5 100644 --- a/src/AsmResolver.DotNet/TokenAllocator.cs +++ b/src/AsmResolver.DotNet/TokenAllocator.cs @@ -20,7 +20,7 @@ internal TokenAllocator(ModuleDefinition module) Initialize(module.DotNetDirectory); } - private void Initialize(IDotNetDirectory? netDirectory) + private void Initialize(DotNetDirectory? netDirectory) { if (netDirectory is null) InitializeDefault(); @@ -34,7 +34,7 @@ private void InitializeDefault() _buckets[(int) index] = new TokenBucket(new MetadataToken(index, 1)); } - private void InitializeTable(IDotNetDirectory netDirectory) + private void InitializeTable(DotNetDirectory netDirectory) { var tableStream = netDirectory.Metadata!.GetStream(); for (TableIndex index = 0; index < TableIndex.Max; index++) diff --git a/src/AsmResolver.PE/DotNet/DotNetDirectory.cs b/src/AsmResolver.PE/DotNet/DotNetDirectory.cs index a19442e53..f731eee4f 100644 --- a/src/AsmResolver.PE/DotNet/DotNetDirectory.cs +++ b/src/AsmResolver.PE/DotNet/DotNetDirectory.cs @@ -7,11 +7,11 @@ namespace AsmResolver.PE.DotNet { /// - /// Provides a basic implementation of a CLR 2.0 data directory present in a PE image containing .NET metadata. + /// Represents a data directory containing the CLR 2.0 header and data directories of a .NET binary. /// - public class DotNetDirectory : SegmentBase, IDotNetDirectory + public class DotNetDirectory : SegmentBase { - private readonly LazyVariable _metadata; + private readonly LazyVariable _metadata; private readonly LazyVariable _resources; private readonly LazyVariable _strongName; private readonly LazyVariable _codeManagerTable; @@ -24,7 +24,7 @@ public class DotNetDirectory : SegmentBase, IDotNetDirectory /// public DotNetDirectory() { - _metadata = new LazyVariable(x => x.GetMetadata()); + _metadata = new LazyVariable(x => x.GetMetadata()); _resources = new LazyVariable(x => x.GetResources()); _strongName = new LazyVariable(x => x.GetStrongName()); _codeManagerTable = new LazyVariable(x => x.GetCodeManagerTable()); @@ -33,77 +33,113 @@ public DotNetDirectory() _managedNativeHeader = new LazyVariable(x => x.GetManagedNativeHeader()); } - /// + /// + /// Gets or sets the major runtime version of the directory format. + /// + /// + /// This field is set to 2 in most .NET binaries. + /// public ushort MajorRuntimeVersion { get; set; } = 2; - /// + /// + /// Gets or sets the minor runtime version of the directory format. + /// + /// + /// This field is set to 5 in most .NET binaries. + /// public ushort MinorRuntimeVersion { get; set; } = 5; - /// - public IMetadata? Metadata + /// + /// Gets or sets the data directory containing the metadata of the .NET binary. + /// + public MetadataDirectory? Metadata { get => _metadata.GetValue(this); set => _metadata.SetValue(value); } - /// + /// + /// Gets or sets the flags associated to the .NET binary. + /// public DotNetDirectoryFlags Flags { get; set; } - /// + /// + /// Gets or sets the metadata token or entry point virtual address, depending on whether + /// is set in . + /// + /// + /// Setting this property will not alter . This means that even if a native entry point is + /// assigned to this property, the flag should be set + /// manually for a properly working .NET module. + /// public DotNetEntryPoint EntryPoint { get; set; } - /// + /// + /// Gets or sets the data directory containing the embedded resources data of the .NET binary (if available). + /// public DotNetResourcesDirectory? DotNetResources { get => _resources.GetValue(this); set => _resources.SetValue(value); } - /// + /// + /// Gets or sets the data directory containing the strong name signature of the .NET binary (if available). + /// public IReadableSegment? StrongName { get => _strongName.GetValue(this); set => _strongName.SetValue(value); } - /// + /// + /// Gets or sets the data directory containing the code manager table of the .NET binary (if available). + /// public IReadableSegment? CodeManagerTable { get => _codeManagerTable.GetValue(this); set => _codeManagerTable.SetValue(value); } - /// + /// + /// Gets or sets the data directory containing the VTable fixups that need to be applied when executing mixed + /// mode applications (if available). + /// public VTableFixupsDirectory? VTableFixups { get => _vtableFixups.GetValue(this); set => _vtableFixups.SetValue(value); } - /// + /// + /// Gets or sets the data directory containing the addresses to native stubs of exports defined in the + /// .NET binary (if available). + /// public IReadableSegment? ExportAddressTable { get => _exportAddressTable.GetValue(this); set => _exportAddressTable.SetValue(value); } - /// + /// + /// Gets or sets the data directory containing the managed native header of a mixed mode application (if available). + /// public IManagedNativeHeader? ManagedNativeHeader { get => _managedNativeHeader.GetValue(this); @@ -143,7 +179,7 @@ public override void Write(IBinaryStreamWriter writer) /// /// This method is called upon initialization of the property /// - protected virtual IMetadata? GetMetadata() => null; + protected virtual MetadataDirectory? GetMetadata() => null; /// /// Obtains the data directory containing the embedded resources data of the .NET binary. diff --git a/src/AsmResolver.PE/DotNet/IDotNetDirectory.cs b/src/AsmResolver.PE/DotNet/IDotNetDirectory.cs deleted file mode 100644 index c8c70d94b..000000000 --- a/src/AsmResolver.PE/DotNet/IDotNetDirectory.cs +++ /dev/null @@ -1,125 +0,0 @@ -using AsmResolver.PE.DotNet.Metadata; -using AsmResolver.PE.DotNet.Resources; -using AsmResolver.PE.DotNet.VTableFixups; - -namespace AsmResolver.PE.DotNet -{ - /// - /// Represents a data directory containing the CLR 2.0 header and data directories of a .NET binary. - /// - public interface IDotNetDirectory : ISegment - { - /// - /// Gets or sets the major runtime version of the directory format. - /// - /// - /// This field is set to 2 in most .NET binaries. - /// - ushort MajorRuntimeVersion - { - get; - set; - } - - /// - /// Gets or sets the minor runtime version of the directory format. - /// - /// - /// This field is set to 5 in most .NET binaries. - /// - ushort MinorRuntimeVersion - { - get; - set; - } - - /// - /// Gets or sets the data directory containing the metadata of the .NET binary. - /// - IMetadata? Metadata - { - get; - set; - } - - /// - /// Gets or sets the flags associated to the .NET binary. - /// - DotNetDirectoryFlags Flags - { - get; - set; - } - - /// - /// Gets or sets the metadata token or entry point virtual address, depending on whether - /// is set in . - /// - /// - /// Setting this property will not alter . This means that even if a native entry point is - /// assigned to this property, the flag should be set - /// manually for a properly working .NET module. - /// - DotNetEntryPoint EntryPoint - { - get; - set; - } - - /// - /// Gets or sets the data directory containing the embedded resources data of the .NET binary (if available). - /// - DotNetResourcesDirectory? DotNetResources - { - get; - set; - } - - /// - /// Gets or sets the data directory containing the strong name signature of the .NET binary (if available). - /// - IReadableSegment? StrongName - { - get; - set; - } - - /// - /// Gets or sets the data directory containing the code manager table of the .NET binary (if available). - /// - IReadableSegment? CodeManagerTable - { - get; - set; - } - - /// - /// Gets or sets the data directory containing the VTable fixups that need to be applied when executing mixed - /// mode applications (if available). - /// - VTableFixupsDirectory? VTableFixups - { - get; - set; - } - - /// - /// Gets or sets the data directory containing the addresses to native stubs of exports defined in the - /// .NET binary (if available). - /// - IReadableSegment? ExportAddressTable - { - get; - set; - } - - /// - /// Gets or sets the data directory containing the managed native header of a mixed mode application (if available). - /// - IManagedNativeHeader? ManagedNativeHeader - { - get; - set; - } - } -} diff --git a/src/AsmResolver.PE/DotNet/Metadata/FieldRvaDataReader.cs b/src/AsmResolver.PE/DotNet/Metadata/FieldRvaDataReader.cs index 361648288..273111ecf 100644 --- a/src/AsmResolver.PE/DotNet/Metadata/FieldRvaDataReader.cs +++ b/src/AsmResolver.PE/DotNet/Metadata/FieldRvaDataReader.cs @@ -19,7 +19,7 @@ public class FieldRvaDataReader : IFieldRvaDataReader public ISegment? ResolveFieldData( IErrorListener listener, Platform platform, - IDotNetDirectory directory, + DotNetDirectory directory, in FieldRvaRow fieldRvaRow) { if (fieldRvaRow.Data.IsBounded) @@ -66,7 +66,7 @@ public class FieldRvaDataReader : IFieldRvaDataReader return null; } - private int DetermineFieldSize(IErrorListener listener, Platform platform, IDotNetDirectory directory, in FieldDefinitionRow field) + private int DetermineFieldSize(IErrorListener listener, Platform platform, DotNetDirectory directory, in FieldDefinitionRow field) { if (!directory.Metadata!.TryGetStream(out var blobStream) || !blobStream.TryGetBlobReaderByIndex(field.Signature, out var reader)) @@ -134,10 +134,10 @@ private int DetermineFieldSize(IErrorListener listener, Platform platform, IDotN } } - private int GetCustomTypeSize(IMetadata metadata, ref BinaryStreamReader reader) + private int GetCustomTypeSize(MetadataDirectory metadataDirectory, ref BinaryStreamReader reader) { if (!reader.TryReadCompressedUInt32(out uint codedIndex) - || !metadata.TryGetStream(out var tablesStream)) + || !metadataDirectory.TryGetStream(out var tablesStream)) { return 0; } diff --git a/src/AsmResolver.PE/DotNet/Metadata/IFieldRvaDataReader.cs b/src/AsmResolver.PE/DotNet/Metadata/IFieldRvaDataReader.cs index 885e58a81..06d2d37f6 100644 --- a/src/AsmResolver.PE/DotNet/Metadata/IFieldRvaDataReader.cs +++ b/src/AsmResolver.PE/DotNet/Metadata/IFieldRvaDataReader.cs @@ -16,7 +16,11 @@ public interface IFieldRvaDataReader /// The .NET directory to read from. /// The row referencing the data. /// The data segment, or null if no data was referenced. - ISegment? ResolveFieldData(IErrorListener listener, Platform platform, IDotNetDirectory directory, - in FieldRvaRow fieldRvaRow); + ISegment? ResolveFieldData( + IErrorListener listener, + Platform platform, + DotNetDirectory directory, + in FieldRvaRow fieldRvaRow + ); } } diff --git a/src/AsmResolver.PE/DotNet/Metadata/ILazyMetadataStream.cs b/src/AsmResolver.PE/DotNet/Metadata/ILazyMetadataStream.cs index 0877d6e7d..064993b80 100644 --- a/src/AsmResolver.PE/DotNet/Metadata/ILazyMetadataStream.cs +++ b/src/AsmResolver.PE/DotNet/Metadata/ILazyMetadataStream.cs @@ -9,6 +9,6 @@ public interface ILazyMetadataStream : IMetadataStream /// Finalizes the initialization process of the metadata stream. /// /// The metadata directory that defines the stream. - void Initialize(IMetadata parentMetadata); + void Initialize(MetadataDirectory parentMetadata); } } diff --git a/src/AsmResolver.PE/DotNet/Metadata/IMetadata.cs b/src/AsmResolver.PE/DotNet/Metadata/IMetadata.cs deleted file mode 100644 index b49a1927c..000000000 --- a/src/AsmResolver.PE/DotNet/Metadata/IMetadata.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -namespace AsmResolver.PE.DotNet.Metadata -{ - /// - /// Represents a data directory containing metadata for a managed executable, including fields from the metadata - /// header, as well as the streams containing metadata tables and blob signatures. - /// - public interface IMetadata : ISegment - { - /// - /// Gets or sets the major version of the metadata directory format. - /// - /// - /// This field is usually set to 1. - /// - ushort MajorVersion - { - get; - set; - } - - /// - /// Gets or sets the minor version of the metadata directory format. - /// - /// - /// This field is usually set to 1. - /// - ushort MinorVersion - { - get; - set; - } - - /// - /// Reserved for future use. - /// - uint Reserved - { - get; - set; - } - - /// - /// Gets or sets the string containing the runtime version that the .NET binary was built for. - /// - string VersionString - { - get; - set; - } - - /// - /// Reserved for future use. - /// - ushort Flags - { - get; - set; - } - - /// - /// Gets a value indicating whether the metadata directory is loaded as Edit-and-Continue metadata. - /// - public bool IsEncMetadata - { - get; - } - - /// - /// Gets a collection of metadata streams that are defined in the metadata header. - /// - IList Streams - { - get; - } - - /// - /// Gets a stream by its name. - /// - /// The name of the stream to search. - /// The stream - /// Occurs when the stream is not present in the metadata directory. - IMetadataStream GetStream(string name); - - /// - /// Gets a stream by its type. - /// - /// The type of the stream. - /// The stream - /// Occurs when the stream is not present in the metadata directory. - TStream GetStream() - where TStream : class, IMetadataStream; - - /// - /// Gets a stream by its name. - /// - /// The name of the stream to search. - /// The found stream, or null if no match was found. - /// true if a match was found, false otherwise. - bool TryGetStream(string name, [NotNullWhen(true)] out IMetadataStream? stream); - - /// - /// Gets a stream by its name. - /// - /// The type of the stream. - /// The found stream, or null if no match was found. - /// true if a match was found, false otherwise. - bool TryGetStream([NotNullWhen(true)] out TStream? stream) - where TStream : class, IMetadataStream; - } -} diff --git a/src/AsmResolver.PE/DotNet/Metadata/Metadata.cs b/src/AsmResolver.PE/DotNet/Metadata/MetadataDirectory.cs similarity index 74% rename from src/AsmResolver.PE/DotNet/Metadata/Metadata.cs rename to src/AsmResolver.PE/DotNet/Metadata/MetadataDirectory.cs index 659da6912..0663d355b 100644 --- a/src/AsmResolver.PE/DotNet/Metadata/Metadata.cs +++ b/src/AsmResolver.PE/DotNet/Metadata/MetadataDirectory.cs @@ -10,55 +10,76 @@ namespace AsmResolver.PE.DotNet.Metadata { /// - /// Provides a basic implementation of a metadata directory in a managed PE. + /// Represents a data directory containing metadata for a managed executable, including fields from the metadata + /// header, as well as the streams containing metadata tables and blob signatures. /// - public class Metadata : SegmentBase, IMetadata + public class MetadataDirectory : SegmentBase { private IList? _streams; - /// + /// + /// Gets or sets the major version of the metadata directory format. + /// + /// + /// This field is usually set to 1. + /// public ushort MajorVersion { get; set; } = 1; - /// + /// + /// Gets or sets the minor version of the metadata directory format. + /// + /// + /// This field is usually set to 1. + /// public ushort MinorVersion { get; set; } = 1; - /// + /// + /// Reserved for future use. + /// public uint Reserved { get; set; } - /// + /// + /// Gets or sets the string containing the runtime version that the .NET binary was built for. + /// public string VersionString { get; set; } = "v4.0.30319"; - /// + /// + /// Reserved for future use. + /// public ushort Flags { get; set; } - /// + /// + /// Gets a value indicating whether the metadata directory is loaded as Edit-and-Continue metadata. + /// public bool IsEncMetadata { get; set; } - /// + /// + /// Gets a collection of metadata streams that are defined in the metadata header. + /// public IList Streams { get @@ -74,28 +95,28 @@ public IList Streams /// /// The path to the file. /// The read metadata. - public static Metadata FromFile(string path) => FromBytes(System.IO.File.ReadAllBytes(path)); + public static MetadataDirectory FromFile(string path) => FromBytes(System.IO.File.ReadAllBytes(path)); /// /// Interprets the provided binary data as a .NET metadata directory. /// /// The raw data. /// The read metadata. - public static Metadata FromBytes(byte[] data) => FromReader(new BinaryStreamReader(data)); + public static MetadataDirectory FromBytes(byte[] data) => FromReader(new BinaryStreamReader(data)); /// /// Reads a .NET metadata directory from a file. /// /// The file to read. /// The read metadata. - public static Metadata FromFile(IInputFile file) => FromReader(file.CreateReader()); + public static MetadataDirectory FromFile(IInputFile file) => FromReader(file.CreateReader()); /// /// Interprets the provided binary stream as a .NET metadata directory. /// /// The input stream. /// The read metadata. - public static Metadata FromReader(BinaryStreamReader reader) + public static MetadataDirectory FromReader(BinaryStreamReader reader) { return FromReader(reader, new MetadataReaderContext(VirtualAddressFactory.Instance)); } @@ -106,9 +127,9 @@ public static Metadata FromReader(BinaryStreamReader reader) /// The input stream. /// The context in which the reader is situated in. /// The read metadata. - public static Metadata FromReader(BinaryStreamReader reader, MetadataReaderContext context) + public static MetadataDirectory FromReader(BinaryStreamReader reader, MetadataReaderContext context) { - return new SerializedMetadata(context, ref reader); + return new SerializedMetadataDirectory(context, ref reader); } /// @@ -206,7 +227,12 @@ protected virtual void WriteStreams(IBinaryStreamWriter writer) Streams[i].Write(writer); } - /// + /// + /// Gets a stream by its name. + /// + /// The name of the stream to search. + /// The stream + /// Occurs when the stream is not present in the metadata directory. public virtual IMetadataStream GetStream(string name) { return TryGetStream(name, out var stream) @@ -214,7 +240,12 @@ public virtual IMetadataStream GetStream(string name) : throw new KeyNotFoundException($"Metadata directory does not contain a stream called {name}."); } - /// + /// + /// Gets a stream by its type. + /// + /// The type of the stream. + /// The stream + /// Occurs when the stream is not present in the metadata directory. public TStream GetStream() where TStream : class, IMetadataStream { @@ -224,7 +255,12 @@ public TStream GetStream() $"Metadata directory does not contain a stream of type {typeof(TStream).FullName}."); } - /// + /// + /// Gets a stream by its name. + /// + /// The name of the stream to search. + /// The found stream, or null if no match was found. + /// true if a match was found, false otherwise. public bool TryGetStream(string name, [NotNullWhen(true)] out IMetadataStream? stream) { bool heapRequested = name is not (TablesStream.CompressedStreamName @@ -234,7 +270,12 @@ or TablesStream.EncStreamName return TryFindStream((c, s) => c.Name == s as string, name, heapRequested, out stream); } - /// + /// + /// Gets a stream by its name. + /// + /// The type of the stream. + /// The found stream, or null if no match was found. + /// true if a match was found, false otherwise. public bool TryGetStream([NotNullWhen(true)] out TStream? stream) where TStream : class, IMetadataStream { diff --git a/src/AsmResolver.PE/DotNet/Metadata/MetadataStreamList.cs b/src/AsmResolver.PE/DotNet/Metadata/MetadataStreamList.cs index 987cced5f..c91e2b930 100644 --- a/src/AsmResolver.PE/DotNet/Metadata/MetadataStreamList.cs +++ b/src/AsmResolver.PE/DotNet/Metadata/MetadataStreamList.cs @@ -11,7 +11,7 @@ public class MetadataStreamList : LazyList { private readonly MetadataReaderContext _context; private readonly MetadataStreamHeader[] _streamHeaders; - private readonly IMetadata _owner; + private readonly MetadataDirectory _owner; private readonly BinaryStreamReader _directoryReader; private readonly MetadataStreamReaderFlags _streamReaderFlags; @@ -24,7 +24,7 @@ public class MetadataStreamList : LazyList /// The stream headers. /// The input stream containing the metadata directory. public MetadataStreamList( - IMetadata owner, + MetadataDirectory owner, MetadataReaderContext context, MetadataStreamReaderFlags streamReaderFlags, MetadataStreamHeader[] streamHeaders, diff --git a/src/AsmResolver.PE/DotNet/Metadata/SerializedMetadata.cs b/src/AsmResolver.PE/DotNet/Metadata/SerializedMetadataDirectory.cs similarity index 96% rename from src/AsmResolver.PE/DotNet/Metadata/SerializedMetadata.cs rename to src/AsmResolver.PE/DotNet/Metadata/SerializedMetadataDirectory.cs index 9298bc2a5..3a42e0f08 100644 --- a/src/AsmResolver.PE/DotNet/Metadata/SerializedMetadata.cs +++ b/src/AsmResolver.PE/DotNet/Metadata/SerializedMetadataDirectory.cs @@ -9,7 +9,7 @@ namespace AsmResolver.PE.DotNet.Metadata /// /// Provides an implementation of a metadata directory that is stored in a PE file. /// - public class SerializedMetadata : Metadata + public class SerializedMetadataDirectory : MetadataDirectory { private readonly MetadataReaderContext _context; private readonly BinaryStreamReader _streamContentsReader; @@ -25,7 +25,7 @@ public class SerializedMetadata : Metadata /// Occurs when any of the arguments are null. /// Occurs when an unsupported metadata directory format was encountered. /// Occurs when the metadata directory header is invalid. - public SerializedMetadata(MetadataReaderContext context, ref BinaryStreamReader directoryReader) + public SerializedMetadataDirectory(MetadataReaderContext context, ref BinaryStreamReader directoryReader) { if (!directoryReader.IsValid) throw new ArgumentNullException(nameof(directoryReader)); diff --git a/src/AsmResolver.PE/DotNet/Metadata/SerializedTableStream.cs b/src/AsmResolver.PE/DotNet/Metadata/SerializedTableStream.cs index f97404fb0..dbfe7d642 100644 --- a/src/AsmResolver.PE/DotNet/Metadata/SerializedTableStream.cs +++ b/src/AsmResolver.PE/DotNet/Metadata/SerializedTableStream.cs @@ -93,7 +93,7 @@ private uint[] ReadRowCounts(ref BinaryStreamReader reader) } /// - public void Initialize(IMetadata parentMetadata) + public void Initialize(MetadataDirectory parentMetadata) { if (parentMetadata.TryGetStream(out PdbStream? pdbStream)) { diff --git a/src/AsmResolver.PE/DotNet/Metadata/Tables/TypeReferenceHash.cs b/src/AsmResolver.PE/DotNet/Metadata/Tables/TypeReferenceHash.cs index 17e94440c..b45b5a9ec 100644 --- a/src/AsmResolver.PE/DotNet/Metadata/Tables/TypeReferenceHash.cs +++ b/src/AsmResolver.PE/DotNet/Metadata/Tables/TypeReferenceHash.cs @@ -37,7 +37,7 @@ public static byte[] GetTypeReferenceHash(this PEImage image) /// The metadata directory to get the TRH from. /// The hash. /// Occurs when the provided image does not contain .NET metadata. - public static byte[] GetTypeReferenceHash(this IMetadata metadata) + public static byte[] GetTypeReferenceHash(this MetadataDirectory metadata) { var tablesStream = metadata.GetStream(); var stringsStream = metadata.GetStream(); diff --git a/src/AsmResolver.PE/DotNet/SerializedDotNetDirectory.cs b/src/AsmResolver.PE/DotNet/SerializedDotNetDirectory.cs index 04d00edbb..ac75cc6a1 100644 --- a/src/AsmResolver.PE/DotNet/SerializedDotNetDirectory.cs +++ b/src/AsmResolver.PE/DotNet/SerializedDotNetDirectory.cs @@ -55,7 +55,7 @@ public SerializedDotNetDirectory(PEReaderContext context, ref BinaryStreamReader } /// - protected override IMetadata? GetMetadata() + protected override MetadataDirectory? GetMetadata() { if (!_metadataDirectory.IsPresentInPE) return null; @@ -66,7 +66,7 @@ public SerializedDotNetDirectory(PEReaderContext context, ref BinaryStreamReader return null; } - return DotNet.Metadata.Metadata.FromReader(directoryReader, MetadataReaderContext.FromReaderContext(_context)); + return MetadataDirectory.FromReader(directoryReader, MetadataReaderContext.FromReaderContext(_context)); } /// diff --git a/src/AsmResolver.PE/PEImage.cs b/src/AsmResolver.PE/PEImage.cs index ccc2720e9..726a8bc91 100644 --- a/src/AsmResolver.PE/PEImage.cs +++ b/src/AsmResolver.PE/PEImage.cs @@ -26,7 +26,7 @@ public class PEImage private readonly LazyVariable _resources; private readonly LazyVariable _exceptions; private IList? _relocations; - private readonly LazyVariable _dotNetDirectory; + private readonly LazyVariable _dotNetDirectory; private IList? _debugData; private readonly LazyVariable _tlsDirectory; private CertificateCollection? _certificates; @@ -183,7 +183,7 @@ public PEImage() _exports = new LazyVariable(x => x.GetExports()); _resources = new LazyVariable(x => x.GetResources()); _exceptions = new LazyVariable(x => x.GetExceptions()); - _dotNetDirectory = new LazyVariable(x => x.GetDotNetDirectory()); + _dotNetDirectory = new LazyVariable(x => x.GetDotNetDirectory()); _tlsDirectory = new LazyVariable(x => x.GetTlsDirectory()); } @@ -354,7 +354,7 @@ public IList Relocations /// /// Gets or sets the data directory containing the CLR 2.0 header of a .NET binary (if available). /// - public IDotNetDirectory? DotNetDirectory + public DotNetDirectory? DotNetDirectory { get => _dotNetDirectory.GetValue(this); set => _dotNetDirectory.SetValue(value); @@ -454,7 +454,7 @@ public CertificateCollection Certificates /// /// This method is called upon initialization of the property. /// - protected virtual IDotNetDirectory? GetDotNetDirectory() => null; + protected virtual DotNetDirectory? GetDotNetDirectory() => null; /// /// Obtains the debug data entries in the PE. diff --git a/src/AsmResolver.PE/SerializedPEImage.cs b/src/AsmResolver.PE/SerializedPEImage.cs index 778af4ab1..d8453676a 100644 --- a/src/AsmResolver.PE/SerializedPEImage.cs +++ b/src/AsmResolver.PE/SerializedPEImage.cs @@ -109,7 +109,7 @@ protected override IList GetRelocations() } /// - protected override IDotNetDirectory? GetDotNetDirectory() + protected override DotNetDirectory? GetDotNetDirectory() { var dataDirectory = PEFile.OptionalHeader.GetDataDirectory(DataDirectoryIndex.ClrDirectory); if (!dataDirectory.IsPresentInPE || !PEFile.TryCreateDataDirectoryReader(dataDirectory, out var reader)) diff --git a/test/AsmResolver.PE.Tests/DotNet/Metadata/MetadataTest.cs b/test/AsmResolver.PE.Tests/DotNet/Metadata/MetadataDirectoryTest.cs similarity index 98% rename from test/AsmResolver.PE.Tests/DotNet/Metadata/MetadataTest.cs rename to test/AsmResolver.PE.Tests/DotNet/Metadata/MetadataDirectoryTest.cs index febac51f4..36f8ed6aa 100644 --- a/test/AsmResolver.PE.Tests/DotNet/Metadata/MetadataTest.cs +++ b/test/AsmResolver.PE.Tests/DotNet/Metadata/MetadataDirectoryTest.cs @@ -8,7 +8,7 @@ namespace AsmResolver.PE.Tests.DotNet.Metadata { - public class MetadataTest + public class MetadataDirectoryTest { [Fact] public void CorrectHeader() @@ -111,7 +111,7 @@ public void PreserveMetadataNoChange() var reader = new BinaryStreamReader(tempStream.ToArray()); var context = MetadataReaderContext.FromReaderContext(new PEReaderContext(peFile)); - var newMetadata = new SerializedMetadata(context, ref reader); + var newMetadata = new SerializedMetadataDirectory(context, ref reader); Assert.Equal(metadata.MajorVersion, newMetadata.MajorVersion); Assert.Equal(metadata.MinorVersion, newMetadata.MinorVersion); diff --git a/test/AsmResolver.PE.Tests/DotNet/Metadata/PdbStreamTest.cs b/test/AsmResolver.PE.Tests/DotNet/Metadata/PdbStreamTest.cs index 66d89ea34..386962fbe 100644 --- a/test/AsmResolver.PE.Tests/DotNet/Metadata/PdbStreamTest.cs +++ b/test/AsmResolver.PE.Tests/DotNet/Metadata/PdbStreamTest.cs @@ -9,14 +9,14 @@ namespace AsmResolver.PE.Tests.DotNet.Metadata { public class PdbStreamTest { - private static IMetadata GetMetadata(bool rebuild) + private static MetadataDirectory GetMetadata(bool rebuild) { - var metadata = PE.DotNet.Metadata.Metadata.FromBytes(Properties.Resources.TheAnswerPortablePdb); + var metadata = MetadataDirectory.FromBytes(Properties.Resources.TheAnswerPortablePdb); if (rebuild) { using var stream = new MemoryStream(); metadata.Write(new BinaryStreamWriter(stream)); - metadata = PE.DotNet.Metadata.Metadata.FromBytes(stream.ToArray()); + metadata = MetadataDirectory.FromBytes(stream.ToArray()); } return metadata; diff --git a/test/AsmResolver.PE.Tests/DotNet/Metadata/Tables/TablesStreamTest.cs b/test/AsmResolver.PE.Tests/DotNet/Metadata/Tables/TablesStreamTest.cs index ee33b0089..dc1c78c69 100644 --- a/test/AsmResolver.PE.Tests/DotNet/Metadata/Tables/TablesStreamTest.cs +++ b/test/AsmResolver.PE.Tests/DotNet/Metadata/Tables/TablesStreamTest.cs @@ -42,7 +42,7 @@ public void PreserveTableStreamNoChange() [Fact] public void SmallExternalIndicesShouldHaveSmallIndicesInTablesStream() { - var pdbMetadata = PE.DotNet.Metadata.Metadata.FromBytes(Properties.Resources.TheAnswerPortablePdb); + var pdbMetadata = PE.DotNet.Metadata.MetadataDirectory.FromBytes(Properties.Resources.TheAnswerPortablePdb); var stream = pdbMetadata.GetStream(); Assert.Equal(IndexSize.Short, stream.GetIndexEncoder(CodedIndex.HasCustomAttribute).IndexSize); } @@ -50,7 +50,7 @@ public void SmallExternalIndicesShouldHaveSmallIndicesInTablesStream() [Fact] public void LargeExternalIndicesShouldHaveLargeIndicesInTablesStream() { - var pdbMetadata = PE.DotNet.Metadata.Metadata.FromBytes(Properties.Resources.LargeIndicesPdb); + var pdbMetadata = PE.DotNet.Metadata.MetadataDirectory.FromBytes(Properties.Resources.LargeIndicesPdb); var stream = pdbMetadata.GetStream(); Assert.Equal(IndexSize.Long, stream.GetIndexEncoder(CodedIndex.HasCustomAttribute).IndexSize); } @@ -58,14 +58,14 @@ public void LargeExternalIndicesShouldHaveLargeIndicesInTablesStream() [Fact] public void PreservePdbTableStreamWithSmallExternalIndicesNoChange() { - var pdbMetadata = PE.DotNet.Metadata.Metadata.FromBytes(Properties.Resources.TheAnswerPortablePdb); + var pdbMetadata = PE.DotNet.Metadata.MetadataDirectory.FromBytes(Properties.Resources.TheAnswerPortablePdb); AssertEquivalentAfterRebuild(pdbMetadata.GetStream()); } [Fact] public void PreservePdbTableStreamWithLargeExternalIndicesNoChange() { - var pdbMetadata = PE.DotNet.Metadata.Metadata.FromBytes(Properties.Resources.LargeIndicesPdb); + var pdbMetadata = PE.DotNet.Metadata.MetadataDirectory.FromBytes(Properties.Resources.LargeIndicesPdb); AssertEquivalentAfterRebuild(pdbMetadata.GetStream()); } @@ -80,7 +80,7 @@ public void GetImpliedTableRowCountFromNonPdbMetadataShouldGetLocalRowCount() [Fact] public void GetImpliedTableRowCountFromPdbMetadataShouldGetExternalRowCount() { - var pdbMetadata = PE.DotNet.Metadata.Metadata.FromBytes(Properties.Resources.TheAnswerPortablePdb); + var pdbMetadata = PE.DotNet.Metadata.MetadataDirectory.FromBytes(Properties.Resources.TheAnswerPortablePdb); var stream = pdbMetadata.GetStream(); Assert.Equal(2u, stream.GetTableRowCount(TableIndex.TypeDef)); Assert.Equal(0u ,(uint) stream.GetTable(TableIndex.TypeDef).Count); @@ -94,7 +94,7 @@ private static void AssertEquivalentAfterRebuild(TablesStream tablesStream) var context = new MetadataReaderContext(VirtualAddressFactory.Instance); var newTablesStream = new SerializedTableStream(context, tablesStream.Name, tempStream.ToArray()); - var metadata = new PE.DotNet.Metadata.Metadata(); + var metadata = new PE.DotNet.Metadata.MetadataDirectory(); if (tablesStream.HasExternalRowCounts) { var pdbStream = new PdbStream(); diff --git a/test/AsmResolver.PE.Tests/DotNet/Resources/DotNetResourcesDirectoryTest.cs b/test/AsmResolver.PE.Tests/DotNet/Resources/DotNetResourcesDirectoryTest.cs index 704d79d69..cabe042ed 100644 --- a/test/AsmResolver.PE.Tests/DotNet/Resources/DotNetResourcesDirectoryTest.cs +++ b/test/AsmResolver.PE.Tests/DotNet/Resources/DotNetResourcesDirectoryTest.cs @@ -9,7 +9,7 @@ namespace AsmResolver.PE.Tests.DotNet.Resources { public class DotNetResourcesDirectoryTest { - private static ManifestResourceRow FindResourceRow(IMetadata metadata, string name) + private static ManifestResourceRow FindResourceRow(MetadataDirectory metadata, string name) { var stringsStream = metadata.GetStream(); var tablesStream = metadata.GetStream(); From fe9d41b53645acedaf04e94abab5678a47afafe5 Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 3 Jun 2024 23:50:30 +0200 Subject: [PATCH 4/8] Remove IExportDirectory. --- .../Exports/Builder/ExportDirectoryBuffer.cs | 4 +- src/AsmResolver.PE/Exports/ExportDirectory.cs | 35 ++++++--- src/AsmResolver.PE/Exports/ExportedSymbol.cs | 6 +- .../Exports/ExportedSymbolCollection.cs | 6 +- .../Exports/IExportDirectory.cs | 75 ------------------- src/AsmResolver.PE/PEImage.cs | 8 +- src/AsmResolver.PE/SerializedPEImage.cs | 2 +- 7 files changed, 39 insertions(+), 97 deletions(-) delete mode 100644 src/AsmResolver.PE/Exports/IExportDirectory.cs diff --git a/src/AsmResolver.PE/Exports/Builder/ExportDirectoryBuffer.cs b/src/AsmResolver.PE/Exports/Builder/ExportDirectoryBuffer.cs index a754c7327..b95067cb9 100644 --- a/src/AsmResolver.PE/Exports/Builder/ExportDirectoryBuffer.cs +++ b/src/AsmResolver.PE/Exports/Builder/ExportDirectoryBuffer.cs @@ -32,7 +32,7 @@ public class ExportDirectoryBuffer : SegmentBase private readonly OrdinalNamePointerTableBuffer _ordinalNamePointerTable; private readonly NameTableBuffer _nameTableBuffer; - private IExportDirectory? _exportDirectory; + private ExportDirectory? _exportDirectory; /// /// Creates a new empty export directory buffer. @@ -63,7 +63,7 @@ public ExportDirectoryBuffer() /// /// The export directory to add. /// Occurs when a second directory is added. - public void AddDirectory(IExportDirectory exportDirectory) + public void AddDirectory(ExportDirectory exportDirectory) { if (!IsEmpty) throw new InvalidProgramException("Cannot add a secondary export directory to the buffer."); diff --git a/src/AsmResolver.PE/Exports/ExportDirectory.cs b/src/AsmResolver.PE/Exports/ExportDirectory.cs index e19649ee1..47a47f409 100644 --- a/src/AsmResolver.PE/Exports/ExportDirectory.cs +++ b/src/AsmResolver.PE/Exports/ExportDirectory.cs @@ -6,9 +6,9 @@ namespace AsmResolver.PE.Exports { /// - /// Provides a basic implementation of the interface. + /// Represents the data directory containing exported symbols that other images can access through dynamic linking. /// - public class ExportDirectory : IExportDirectory + public class ExportDirectory { private readonly LazyVariable _name; private IList? _exports; @@ -30,49 +30,66 @@ public ExportDirectory(string name) _name = new LazyVariable(name ?? throw new ArgumentNullException(nameof(name))); } - /// + /// + /// Gets or sets the flags associated to the export directory. + /// + /// + /// This field is reserved and should be zero. + /// public uint ExportFlags { get; set; } - /// + /// + /// Gets or sets the time and date that the exports data was created. + /// public uint TimeDateStamp { get; set; } = 0xFFFFFFFF; - /// + /// + /// Gets or sets the user major version number. + /// public ushort MajorVersion { get; set; } - /// + /// + /// Gets or sets the user minor version number. + /// public ushort MinorVersion { get; set; } - /// + /// + /// Gets or sets the name of the exports directory. + /// public string? Name { get => _name.GetValue(this); set => _name.SetValue(value); } - /// + /// + /// Gets or sets the base ordinal of the exports directory. + /// public uint BaseOrdinal { get; set; } = 1; - /// + /// + /// Gets an ordered list of symbols that are exported by the portable executable (PE) image. + /// public IList Entries { get diff --git a/src/AsmResolver.PE/Exports/ExportedSymbol.cs b/src/AsmResolver.PE/Exports/ExportedSymbol.cs index 2e52cf49e..cb36185ba 100644 --- a/src/AsmResolver.PE/Exports/ExportedSymbol.cs +++ b/src/AsmResolver.PE/Exports/ExportedSymbol.cs @@ -8,7 +8,7 @@ namespace AsmResolver.PE.Exports /// /// Represents a single symbol that is exported by a dynamically linked library. /// - public class ExportedSymbol : IOwnedCollectionElement, ISymbol + public class ExportedSymbol : IOwnedCollectionElement, ISymbol { /// /// Creates a new symbol that is exported by ordinal. @@ -47,13 +47,13 @@ public ExportedSymbol(ISegmentReference address, string? name, string? forwarder /// /// Gets the export directory this symbol was added to (if available). /// - public IExportDirectory? ParentDirectory + public ExportDirectory? ParentDirectory { get; private set; } - IExportDirectory? IOwnedCollectionElement.Owner + ExportDirectory? IOwnedCollectionElement.Owner { get => ParentDirectory; set => ParentDirectory = value; diff --git a/src/AsmResolver.PE/Exports/ExportedSymbolCollection.cs b/src/AsmResolver.PE/Exports/ExportedSymbolCollection.cs index 7423e10ef..9a3ad4aee 100644 --- a/src/AsmResolver.PE/Exports/ExportedSymbolCollection.cs +++ b/src/AsmResolver.PE/Exports/ExportedSymbolCollection.cs @@ -7,13 +7,13 @@ namespace AsmResolver.PE.Exports /// /// Represents a collection of exported symbols within an export data directory. /// - public class ExportedSymbolCollection : OwnedCollection + public class ExportedSymbolCollection : OwnedCollection { /// /// Creates a new instance of the exported symbol collection. /// /// - public ExportedSymbolCollection(IExportDirectory owner) + public ExportedSymbolCollection(ExportDirectory owner) : base(owner) { } @@ -80,4 +80,4 @@ protected override void OnSetItem(int index, ExportedSymbol item) } } } -} \ No newline at end of file +} diff --git a/src/AsmResolver.PE/Exports/IExportDirectory.cs b/src/AsmResolver.PE/Exports/IExportDirectory.cs deleted file mode 100644 index b235da1db..000000000 --- a/src/AsmResolver.PE/Exports/IExportDirectory.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System.Collections.Generic; - -namespace AsmResolver.PE.Exports -{ - /// - /// Represents the data directory containing exported symbols that other images can access through dynamic linking. - /// - public interface IExportDirectory - { - /// - /// Gets or sets the flags associated to the export directory. - /// - /// - /// This field is reserved and should be zero. - /// - uint ExportFlags - { - get; - set; - } - - /// - /// Gets or sets the time and date that the exports data was created. - /// - uint TimeDateStamp - { - get; - set; - } - - /// - /// Gets or sets the user major version number. - /// - ushort MajorVersion - { - get; - set; - } - - /// - /// Gets or sets the user minor version number. - /// - ushort MinorVersion - { - get; - set; - } - - /// - /// Gets or sets the name of the exports directory. - /// - string? Name - { - get; - set; - } - - /// - /// Gets or sets the base ordinal of the exports directory. - /// - uint BaseOrdinal - { - get; - set; - } - - /// - /// Gets an ordered list of symbols that are exported by the portable executable (PE) image. - /// - IList Entries - { - get; - } - } -} diff --git a/src/AsmResolver.PE/PEImage.cs b/src/AsmResolver.PE/PEImage.cs index 726a8bc91..e5c7b4647 100644 --- a/src/AsmResolver.PE/PEImage.cs +++ b/src/AsmResolver.PE/PEImage.cs @@ -22,7 +22,7 @@ namespace AsmResolver.PE public class PEImage { private IList? _imports; - private readonly LazyVariable _exports; + private readonly LazyVariable _exports; private readonly LazyVariable _resources; private readonly LazyVariable _exceptions; private IList? _relocations; @@ -180,7 +180,7 @@ public static PEImage FromFile(PEFile peFile, PEReaderParameters readerParameter /// public PEImage() { - _exports = new LazyVariable(x => x.GetExports()); + _exports = new LazyVariable(x => x.GetExports()); _resources = new LazyVariable(x => x.GetResources()); _exceptions = new LazyVariable(x => x.GetExceptions()); _dotNetDirectory = new LazyVariable(x => x.GetDotNetDirectory()); @@ -314,7 +314,7 @@ public IList Imports /// /// Gets or sets the exports directory in the PE, if available. /// - public IExportDirectory? Exports + public ExportDirectory? Exports { get => _exports.GetValue(this); set => _exports.SetValue(value); @@ -418,7 +418,7 @@ public CertificateCollection Certificates /// /// This method is called upon initialization of the property. /// - protected virtual IExportDirectory? GetExports() => null; + protected virtual ExportDirectory? GetExports() => null; /// /// Obtains the root resource directory in the PE. diff --git a/src/AsmResolver.PE/SerializedPEImage.cs b/src/AsmResolver.PE/SerializedPEImage.cs index d8453676a..9c786f2d8 100644 --- a/src/AsmResolver.PE/SerializedPEImage.cs +++ b/src/AsmResolver.PE/SerializedPEImage.cs @@ -66,7 +66,7 @@ protected override IList GetImports() } /// - protected override IExportDirectory? GetExports() + protected override ExportDirectory? GetExports() { var dataDirectory = PEFile.OptionalHeader.GetDataDirectory(DataDirectoryIndex.ExportDirectory); if (!dataDirectory.IsPresentInPE || !PEFile.TryCreateDataDirectoryReader(dataDirectory, out var reader)) From a34651a6c13d0394e6b1d8c096c416e579eb085d Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 3 Jun 2024 23:55:58 +0200 Subject: [PATCH 5/8] Remove IImportedModule. --- .../Code/Native/NativeSymbolsProvider.cs | 8 +-- .../Builder/ManagedPEFileBuilder.cs | 2 +- .../Imports/Builder/HintNameTableBuffer.cs | 10 ++-- .../Imports/Builder/ImportDirectoryBuffer.cs | 4 +- .../Builder/ImportDirectoryBufferBase.cs | 12 ++--- src/AsmResolver.PE/Imports/IImportedModule.cs | 49 ------------------- src/AsmResolver.PE/Imports/ImportHash.cs | 2 +- src/AsmResolver.PE/Imports/ImportedModule.cs | 30 ++++++++---- src/AsmResolver.PE/Imports/ImportedSymbol.cs | 6 +-- .../Imports/SerializedImportedModule.cs | 2 +- .../Imports/SerializedImportedModuleList.cs | 2 +- src/AsmResolver.PE/PEImage.cs | 6 +-- src/AsmResolver.PE/SerializedPEImage.cs | 4 +- 13 files changed, 49 insertions(+), 88 deletions(-) delete mode 100644 src/AsmResolver.PE/Imports/IImportedModule.cs diff --git a/src/AsmResolver.DotNet/Code/Native/NativeSymbolsProvider.cs b/src/AsmResolver.DotNet/Code/Native/NativeSymbolsProvider.cs index e84dcae85..65fdd1730 100644 --- a/src/AsmResolver.DotNet/Code/Native/NativeSymbolsProvider.cs +++ b/src/AsmResolver.DotNet/Code/Native/NativeSymbolsProvider.cs @@ -16,7 +16,7 @@ namespace AsmResolver.DotNet.Code.Native /// public class NativeSymbolsProvider : INativeSymbolsProvider { - private readonly Dictionary _modules = new(); + private readonly Dictionary _modules = new(); private readonly Dictionary _relocations = new(); private readonly Dictionary _fixedExportedSymbols = new(); @@ -52,7 +52,7 @@ private ImportedSymbol GetImportedSymbol(ImportedSymbol symbol) return newSymbol; } - private IImportedModule GetModuleByName(string name) + private ImportedModule GetModuleByName(string name) { if (!_modules.TryGetValue(name, out var module)) { @@ -65,7 +65,7 @@ private IImportedModule GetModuleByName(string name) private static bool TryGetSimilarSymbol( ImportedSymbol symbol, - IImportedModule module, + ImportedModule module, [NotNullWhen(true)] out ImportedSymbol? existingSymbol) { for (int i = 0; i < module.Symbols.Count; i++) @@ -136,7 +136,7 @@ public void RegisterExportedSymbol(ExportedSymbol symbol, uint? newOrdinal) /// Gets a collection of all imported external modules. /// /// The modules. - public IEnumerable GetImportedModules() => _modules.Values; + public IEnumerable GetImportedModules() => _modules.Values; /// /// Gets a collection of all base relocations that need to be applied in the final PE image. diff --git a/src/AsmResolver.PE/Builder/ManagedPEFileBuilder.cs b/src/AsmResolver.PE/Builder/ManagedPEFileBuilder.cs index ca186158a..39d691249 100644 --- a/src/AsmResolver.PE/Builder/ManagedPEFileBuilder.cs +++ b/src/AsmResolver.PE/Builder/ManagedPEFileBuilder.cs @@ -266,7 +266,7 @@ out var entryPointSymbol } } - private static List CollectImportedModules( + private static List CollectImportedModules( PEImage image, bool requireClrEntryPoint, string clrEntryPointName, diff --git a/src/AsmResolver.PE/Imports/Builder/HintNameTableBuffer.cs b/src/AsmResolver.PE/Imports/Builder/HintNameTableBuffer.cs index 62275e716..832463199 100644 --- a/src/AsmResolver.PE/Imports/Builder/HintNameTableBuffer.cs +++ b/src/AsmResolver.PE/Imports/Builder/HintNameTableBuffer.cs @@ -9,8 +9,8 @@ namespace AsmResolver.PE.Imports.Builder /// public class HintNameTableBuffer : SegmentBase { - private readonly List _modules = new(); - private readonly Dictionary _moduleNameOffsets = new(); + private readonly List _modules = new(); + private readonly Dictionary _moduleNameOffsets = new(); private readonly Dictionary _hintNameOffsets = new(); private uint _length; @@ -46,7 +46,7 @@ public override void UpdateOffsets(in RelocationParameters parameters) /// Adds the name of the module and the names of all named entries to the hint-name table. /// /// The module to add. - public void AddModule(IImportedModule module) + public void AddModule(ImportedModule module) { _modules.Add(module); } @@ -60,7 +60,7 @@ public void AddModule(IImportedModule module) /// This method should only be used after the hint-name table has been relocated to the right location in the /// PE file. /// - public uint GetModuleNameRva(IImportedModule module) => Rva + _moduleNameOffsets[module]; + public uint GetModuleNameRva(ImportedModule module) => Rva + _moduleNameOffsets[module]; /// /// Gets the virtual address to the beginning of the hint-name pair associated to an imported member. @@ -99,7 +99,7 @@ private static void WriteHintName(IBinaryStreamWriter writer, ushort hint, strin writer.Align(2); } - private static void WriteModuleName(IBinaryStreamWriter writer, IImportedModule module) + private static void WriteModuleName(IBinaryStreamWriter writer, ImportedModule module) { writer.WriteAsciiString(module.Name ?? string.Empty); writer.WriteByte(0); diff --git a/src/AsmResolver.PE/Imports/Builder/ImportDirectoryBuffer.cs b/src/AsmResolver.PE/Imports/Builder/ImportDirectoryBuffer.cs index 19af5bb67..ec210fb93 100644 --- a/src/AsmResolver.PE/Imports/Builder/ImportDirectoryBuffer.cs +++ b/src/AsmResolver.PE/Imports/Builder/ImportDirectoryBuffer.cs @@ -33,7 +33,7 @@ public ImportAddressDirectoryBuffer ImportAddressDirectory public bool IsEmpty => _entriesLength == 0; /// - public override void AddModule(IImportedModule module) + public override void AddModule(ImportedModule module) { if (_entriesLength == 0) _entriesLength = SerializedImportedModule.ModuleImportSize; @@ -83,7 +83,7 @@ private void WriteModuleImportEntries(IBinaryStreamWriter writer) WriteModuleImportEntry(writer, 0, 0, 0, 0, 0); } - private void WriteModuleImportEntry(IBinaryStreamWriter writer, IImportedModule module) + private void WriteModuleImportEntry(IBinaryStreamWriter writer, ImportedModule module) { WriteModuleImportEntry(writer, GetModuleThunkTable(module).Rva, diff --git a/src/AsmResolver.PE/Imports/Builder/ImportDirectoryBufferBase.cs b/src/AsmResolver.PE/Imports/Builder/ImportDirectoryBufferBase.cs index 02e45f163..aab509d3d 100644 --- a/src/AsmResolver.PE/Imports/Builder/ImportDirectoryBufferBase.cs +++ b/src/AsmResolver.PE/Imports/Builder/ImportDirectoryBufferBase.cs @@ -10,7 +10,7 @@ namespace AsmResolver.PE.Imports.Builder /// public abstract class ImportDirectoryBufferBase : SegmentBase, IImportAddressProvider { - private readonly Dictionary _lookupTables = new(); + private readonly Dictionary _lookupTables = new(); private uint _lookupTablesLength; /// @@ -40,10 +40,10 @@ public bool Is32Bit /// /// Gets an ordered list of modules that were added to the buffer. /// - protected IList Modules + protected IList Modules { get; - } = new List(); + } = new List(); /// /// Gets the hint-name table that is used to reference names of modules or members. @@ -57,7 +57,7 @@ public HintNameTableBuffer HintNameTable /// Creates a thunk table for a module and its imported members, and adds it to the buffer. /// /// The module to add. - public virtual void AddModule(IImportedModule module) + public virtual void AddModule(ImportedModule module) { Modules.Add(module); AddLookupTable(module); @@ -68,7 +68,7 @@ public virtual void AddModule(IImportedModule module) /// /// The module to get the associated thunk table for. /// The thunk table. - public ThunkTableBuffer GetModuleThunkTable(IImportedModule module) => _lookupTables[module]; + public ThunkTableBuffer GetModuleThunkTable(ImportedModule module) => _lookupTables[module]; /// public uint GetThunkRva(string moduleName, string memberName) @@ -84,7 +84,7 @@ public uint GetThunkRva(string moduleName, string memberName) return GetModuleThunkTable(module).GetMemberThunkRva(member); } - private void AddLookupTable(IImportedModule module) + private void AddLookupTable(ImportedModule module) { var lookupTable = CreateThunkTable(); foreach (var member in module.Symbols) diff --git a/src/AsmResolver.PE/Imports/IImportedModule.cs b/src/AsmResolver.PE/Imports/IImportedModule.cs deleted file mode 100644 index 8c81f75d0..000000000 --- a/src/AsmResolver.PE/Imports/IImportedModule.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; - -namespace AsmResolver.PE.Imports -{ - /// - /// Represents a single module that was imported into a portable executable as part of the imports data directory. - /// Each instance represents one entry in the imports directory. - /// - public interface IImportedModule - { - /// - /// Gets or sets the name of the module that was imported. - /// - string? Name - { - get; - set; - } - - /// - /// Gets or sets the time stamp that the module was loaded into memory. - /// - /// - /// This field is always 0 if the PE was read from the disk. - /// - uint TimeDateStamp - { - get; - set; - } - - /// - /// Gets or sets the index of the first member that is a forwarder. - /// - uint ForwarderChain - { - get; - set; - } - - /// - /// Gets a collection of members from the module that were imported. - /// - IList Symbols - { - get; - } - } -} diff --git a/src/AsmResolver.PE/Imports/ImportHash.cs b/src/AsmResolver.PE/Imports/ImportHash.cs index 081cb93ec..16911eb7c 100644 --- a/src/AsmResolver.PE/Imports/ImportHash.cs +++ b/src/AsmResolver.PE/Imports/ImportHash.cs @@ -54,7 +54,7 @@ public static byte[] GetImportHash(this PEImage image, ISymbolResolver symbolRes return md5.ComputeHash(Encoding.ASCII.GetBytes(StringShim.Join(",", elements))); } - private static string FormatModuleName(IImportedModule module) + private static string FormatModuleName(ImportedModule module) { string name = module.Name!; if (string.IsNullOrEmpty(name)) diff --git a/src/AsmResolver.PE/Imports/ImportedModule.cs b/src/AsmResolver.PE/Imports/ImportedModule.cs index 7def55b79..c429eeca2 100644 --- a/src/AsmResolver.PE/Imports/ImportedModule.cs +++ b/src/AsmResolver.PE/Imports/ImportedModule.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Threading; using AsmResolver.Collections; using AsmResolver.IO; @@ -8,10 +7,10 @@ namespace AsmResolver.PE.Imports { /// - /// Provides an implementation of the class, which can be instantiated and added - /// to an existing portable executable image. + /// Represents a single module that was imported into a portable executable as part of the imports data directory. + /// Each instance represents one entry in the imports directory. /// - public class ImportedModule : IImportedModule + public class ImportedModule { private IList? _members; @@ -31,28 +30,39 @@ public ImportedModule(string name) Name = name ?? throw new ArgumentNullException(nameof(name)); } - /// + /// + /// Gets or sets the name of the module that was imported. + /// public string? Name { get; set; } - /// + /// + /// Gets or sets the time stamp that the module was loaded into memory. + /// + /// + /// This field is always 0 if the PE was read from the disk. + /// public uint TimeDateStamp { get; set; } - /// + /// + /// Gets or sets the index of the first member that is a forwarder. + /// public uint ForwarderChain { get; set; } - /// + /// + /// Gets a collection of members from the module that were imported. + /// public IList Symbols { get @@ -68,7 +78,7 @@ public IList Symbols /// The reader context. /// The input stream to read from. /// - public static IImportedModule? FromReader(PEReaderContext context, ref BinaryStreamReader reader) + public static ImportedModule? FromReader(PEReaderContext context, ref BinaryStreamReader reader) { var entry = new SerializedImportedModule(context, ref reader); return entry.IsEmpty @@ -84,7 +94,7 @@ public IList Symbols /// /// The members list. protected virtual IList GetSymbols() => - new OwnedCollection(this); + new OwnedCollection(this); /// public override string ToString() => $"{Name} ({Symbols.Count.ToString()} symbols)"; diff --git a/src/AsmResolver.PE/Imports/ImportedSymbol.cs b/src/AsmResolver.PE/Imports/ImportedSymbol.cs index e58a798ce..9a38a2d40 100644 --- a/src/AsmResolver.PE/Imports/ImportedSymbol.cs +++ b/src/AsmResolver.PE/Imports/ImportedSymbol.cs @@ -7,7 +7,7 @@ namespace AsmResolver.PE.Imports /// /// Represents one member of an external module that was imported into a PE image. /// - public class ImportedSymbol : IOwnedCollectionElement, ISymbol + public class ImportedSymbol : IOwnedCollectionElement, ISymbol { private ushort _ordinalOrHint; @@ -34,14 +34,14 @@ public ImportedSymbol(ushort hint, string name) /// /// Gets the module that defines the symbol. /// - public IImportedModule? DeclaringModule + public ImportedModule? DeclaringModule { get; private set; } /// - IImportedModule? IOwnedCollectionElement.Owner + ImportedModule? IOwnedCollectionElement.Owner { get => DeclaringModule; set => DeclaringModule = value; diff --git a/src/AsmResolver.PE/Imports/SerializedImportedModule.cs b/src/AsmResolver.PE/Imports/SerializedImportedModule.cs index 3f5ae63f8..cd7984120 100644 --- a/src/AsmResolver.PE/Imports/SerializedImportedModule.cs +++ b/src/AsmResolver.PE/Imports/SerializedImportedModule.cs @@ -62,7 +62,7 @@ public SerializedImportedModule(PEReaderContext context, ref BinaryStreamReader /// protected override IList GetSymbols() { - var result = new OwnedCollection(this); + var result = new OwnedCollection(this); if (IsEmpty) return result; diff --git a/src/AsmResolver.PE/Imports/SerializedImportedModuleList.cs b/src/AsmResolver.PE/Imports/SerializedImportedModuleList.cs index 92cfef062..17e59c416 100644 --- a/src/AsmResolver.PE/Imports/SerializedImportedModuleList.cs +++ b/src/AsmResolver.PE/Imports/SerializedImportedModuleList.cs @@ -9,7 +9,7 @@ namespace AsmResolver.PE.Imports /// Provides a lazy-initialized list of module import entries that is stored in a PE file. /// [DebuggerDisplay("Count = {" + nameof(Count) + "}")] - public class SerializedImportedModuleList : LazyList + public class SerializedImportedModuleList : LazyList { private readonly PEReaderContext _context; private readonly DataDirectory _dataDirectory; diff --git a/src/AsmResolver.PE/PEImage.cs b/src/AsmResolver.PE/PEImage.cs index e5c7b4647..09f968a89 100644 --- a/src/AsmResolver.PE/PEImage.cs +++ b/src/AsmResolver.PE/PEImage.cs @@ -21,7 +21,7 @@ namespace AsmResolver.PE /// public class PEImage { - private IList? _imports; + private IList? _imports; private readonly LazyVariable _exports; private readonly LazyVariable _resources; private readonly LazyVariable _exceptions; @@ -301,7 +301,7 @@ public ulong ImageBase /// /// Gets a collection of modules that were imported into the PE, according to the import data directory. /// - public IList Imports + public IList Imports { get { @@ -409,7 +409,7 @@ public CertificateCollection Certificates /// /// This method is called upon initialization of the property. /// - protected virtual IList GetImports() => new List(); + protected virtual IList GetImports() => new List(); /// /// Obtains the list of symbols that were exported from the PE. diff --git a/src/AsmResolver.PE/SerializedPEImage.cs b/src/AsmResolver.PE/SerializedPEImage.cs index 9c786f2d8..71d15870b 100644 --- a/src/AsmResolver.PE/SerializedPEImage.cs +++ b/src/AsmResolver.PE/SerializedPEImage.cs @@ -57,12 +57,12 @@ public PEReaderContext ReaderContext } /// - protected override IList GetImports() + protected override IList GetImports() { var dataDirectory = PEFile.OptionalHeader.GetDataDirectory(DataDirectoryIndex.ImportDirectory); return dataDirectory.IsPresentInPE ? new SerializedImportedModuleList(ReaderContext, dataDirectory) - : new List(); + : new List(); } /// From fe610dd9a95c91f45ab94d9e76cb698926ea03bc Mon Sep 17 00:00:00 2001 From: Washi Date: Mon, 3 Jun 2024 23:58:45 +0200 Subject: [PATCH 6/8] Remove ITlsDirectory. --- src/AsmResolver.PE/PEImage.cs | 8 +-- src/AsmResolver.PE/SerializedPEImage.cs | 2 +- src/AsmResolver.PE/Tls/ITlsDirectory.cs | 65 ------------------------- src/AsmResolver.PE/Tls/TlsDirectory.cs | 32 +++++++++--- 4 files changed, 29 insertions(+), 78 deletions(-) delete mode 100644 src/AsmResolver.PE/Tls/ITlsDirectory.cs diff --git a/src/AsmResolver.PE/PEImage.cs b/src/AsmResolver.PE/PEImage.cs index 09f968a89..61b050224 100644 --- a/src/AsmResolver.PE/PEImage.cs +++ b/src/AsmResolver.PE/PEImage.cs @@ -28,7 +28,7 @@ public class PEImage private IList? _relocations; private readonly LazyVariable _dotNetDirectory; private IList? _debugData; - private readonly LazyVariable _tlsDirectory; + private readonly LazyVariable _tlsDirectory; private CertificateCollection? _certificates; /// @@ -184,7 +184,7 @@ public PEImage() _resources = new LazyVariable(x => x.GetResources()); _exceptions = new LazyVariable(x => x.GetExceptions()); _dotNetDirectory = new LazyVariable(x => x.GetDotNetDirectory()); - _tlsDirectory = new LazyVariable(x => x.GetTlsDirectory()); + _tlsDirectory = new LazyVariable(x => x.GetTlsDirectory()); } /// @@ -376,7 +376,7 @@ public IList DebugData /// /// Gets or sets the data directory containing the Thread-Local Storage (TLS) data. /// - public ITlsDirectory? TlsDirectory + public TlsDirectory? TlsDirectory { get => _tlsDirectory.GetValue(this); set => _tlsDirectory.SetValue(value); @@ -472,7 +472,7 @@ public CertificateCollection Certificates /// /// This method is called upon initialization of the property. /// - protected virtual ITlsDirectory? GetTlsDirectory() => null; + protected virtual TlsDirectory? GetTlsDirectory() => null; /// /// Obtains the data directory containing the attribute certificates table of the executable. diff --git a/src/AsmResolver.PE/SerializedPEImage.cs b/src/AsmResolver.PE/SerializedPEImage.cs index 71d15870b..8dd4941f8 100644 --- a/src/AsmResolver.PE/SerializedPEImage.cs +++ b/src/AsmResolver.PE/SerializedPEImage.cs @@ -135,7 +135,7 @@ protected override IList GetDebugData() } /// - protected override ITlsDirectory? GetTlsDirectory() + protected override TlsDirectory? GetTlsDirectory() { var dataDirectory = PEFile.OptionalHeader.GetDataDirectory(DataDirectoryIndex.TlsDirectory); if (!dataDirectory.IsPresentInPE || !PEFile.TryCreateDataDirectoryReader(dataDirectory, out var reader)) diff --git a/src/AsmResolver.PE/Tls/ITlsDirectory.cs b/src/AsmResolver.PE/Tls/ITlsDirectory.cs deleted file mode 100644 index 9c48ea052..000000000 --- a/src/AsmResolver.PE/Tls/ITlsDirectory.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Collections.Generic; -using AsmResolver.Collections; -using AsmResolver.PE.Relocations; - -namespace AsmResolver.PE.Tls -{ - /// - /// Represents the data directory containing Thread-Local Storage (TLS) data. - /// - public interface ITlsDirectory : ISegment - { - /// - /// Gets or sets the block of data that is used as a template to initialize TLS data. The system copies all - /// of this data each time a thread is created. - /// - IReadableSegment? TemplateData - { - get; - set; - } - - /// - /// The location to receive the TLS index, which the loader assigns - /// - ISegmentReference Index - { - get; - set; - } - - /// - /// Gets a table of function callbacks that need to be called upon every thread creation. - /// - ReferenceTable CallbackFunctions - { - get; - } - - /// - /// Gets or sets the number of zero bytes that need to be appended after the template data referenced by - /// . - /// - uint SizeOfZeroFill - { - get; - set; - } - - /// - /// Gets or sets the characteristics that are assigned to this directory. - /// - TlsCharacteristics Characteristics - { - get; - set; - } - - /// - /// Obtains a collection of base address relocations that need to be applied to the TLS data directory - /// after the image was loaded into memory. - /// - /// The required base relocations. - IEnumerable GetRequiredBaseRelocations(); - } -} diff --git a/src/AsmResolver.PE/Tls/TlsDirectory.cs b/src/AsmResolver.PE/Tls/TlsDirectory.cs index 1cd652221..b2135a22c 100644 --- a/src/AsmResolver.PE/Tls/TlsDirectory.cs +++ b/src/AsmResolver.PE/Tls/TlsDirectory.cs @@ -7,9 +7,9 @@ namespace AsmResolver.PE.Tls { /// - /// Provides a basic implementation of the interface. + /// Represents the data directory containing Thread-Local Storage (TLS) data. /// - public class TlsDirectory : SegmentBase, ITlsDirectory + public class TlsDirectory : SegmentBase { private readonly LazyVariable _templateData; private ReferenceTable? _callbackFunctions; @@ -25,21 +25,28 @@ public TlsDirectory() Index = SegmentReference.Null; } - /// + /// + /// Gets or sets the block of data that is used as a template to initialize TLS data. The system copies all + /// of this data each time a thread is created. + /// public IReadableSegment? TemplateData { get => _templateData.GetValue(this); set => _templateData.SetValue(value); } - /// + /// + /// The location to receive the TLS index, which the loader assigns + /// public ISegmentReference Index { get; set; } - /// + /// + /// Gets a table of function callbacks that need to be called upon every thread creation. + /// public ReferenceTable CallbackFunctions { get @@ -50,14 +57,19 @@ public ReferenceTable CallbackFunctions } } - /// + /// + /// Gets or sets the number of zero bytes that need to be appended after the template data referenced by + /// . + /// public uint SizeOfZeroFill { get; set; } - /// + /// + /// Gets or sets the characteristics that are assigned to this directory. + /// public TlsCharacteristics Characteristics { get; @@ -90,7 +102,11 @@ public override void UpdateOffsets(in RelocationParameters parameters) /// protected virtual ReferenceTable GetCallbackFunctions() => new(ReferenceTableAttributes.Va | ReferenceTableAttributes.Adaptive | ReferenceTableAttributes.ZeroTerminated); - /// + /// + /// Obtains a collection of base address relocations that need to be applied to the TLS data directory + /// after the image was loaded into memory. + /// + /// The required base relocations. public IEnumerable GetRequiredBaseRelocations() { int pointerSize = _is32Bit ? sizeof(uint) : sizeof(ulong); From 9848eddbabb8fc44ffb4337c69035aa73121cbf1 Mon Sep 17 00:00:00 2001 From: Washi Date: Tue, 4 Jun 2024 00:11:48 +0200 Subject: [PATCH 7/8] Remove IResourceData and IResourceDirectory. --- .../Bundles/BundlerParameters.cs | 4 +- src/AsmResolver.DotNet/ModuleDefinition.cs | 8 +- .../Serialized/SerializedModuleDefinition.cs | 2 +- .../IWin32Resource.cs | 2 +- .../Icon/IconGroupDirectory.cs | 12 +- .../Icon/IconResource.cs | 10 +- .../Version/VersionInfoResource.cs | 19 +-- src/AsmResolver.PE/PEImage.cs | 8 +- src/AsmResolver.PE/SerializedPEImage.cs | 2 +- .../Builder/ResourceDataTableBuffer.cs | 6 +- .../Builder/ResourceDirectoryBuffer.cs | 10 +- .../Builder/ResourceDirectoryTableBuffer.cs | 21 +-- .../Win32Resources/IResourceData.cs | 47 ------ .../Win32Resources/IResourceDirectory.cs | 158 ------------------ .../Win32Resources/IResourceEntry.cs | 4 +- .../Win32Resources/ResourceData.cs | 30 +++- .../Win32Resources/ResourceDirectory.cs | 135 +++++++++++---- .../SerializedResourceDirectory.cs | 2 +- .../ModuleDefinitionTest.cs | 10 +- .../Win32Resources/ResourceDirectoryTest.cs | 16 +- 20 files changed, 191 insertions(+), 315 deletions(-) delete mode 100644 src/AsmResolver.PE/Win32Resources/IResourceData.cs delete mode 100644 src/AsmResolver.PE/Win32Resources/IResourceDirectory.cs diff --git a/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs b/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs index b0b78130f..1d020fc5f 100644 --- a/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs +++ b/src/AsmResolver.DotNet/Bundles/BundlerParameters.cs @@ -159,7 +159,7 @@ public BundlerParameters( byte[] appHostTemplate, string appBinaryPath, SubSystem subSystem, - IResourceDirectory? resources) + ResourceDirectory? resources) { ApplicationHostTemplate = appHostTemplate; ApplicationBinaryPath = appBinaryPath; @@ -222,7 +222,7 @@ public bool IsArm64Linux /// This field is ignored if is set to true, or /// does not contain a proper PE image. /// - public IResourceDirectory? Resources + public ResourceDirectory? Resources { get; set; diff --git a/src/AsmResolver.DotNet/ModuleDefinition.cs b/src/AsmResolver.DotNet/ModuleDefinition.cs index 22cd72efd..1e0b32082 100644 --- a/src/AsmResolver.DotNet/ModuleDefinition.cs +++ b/src/AsmResolver.DotNet/ModuleDefinition.cs @@ -48,7 +48,7 @@ public class ModuleDefinition : private TokenAllocator? _tokenAllocator; private readonly LazyVariable _runtimeVersion; - private readonly LazyVariable _nativeResources; + private readonly LazyVariable _nativeResources; private IList? _debugData; private ReferenceImporter? _defaultImporter; @@ -275,7 +275,7 @@ protected ModuleDefinition(MetadataToken token) _encBaseId = new LazyVariable(x => x.GetEncBaseId()); _managedEntryPoint = new LazyVariable(x => x.GetManagedEntryPoint()); _runtimeVersion = new LazyVariable(x => x.GetRuntimeVersion()); - _nativeResources = new LazyVariable(x => x.GetNativeResources()); + _nativeResources = new LazyVariable(x => x.GetNativeResources()); Attributes = DotNetDirectoryFlags.ILOnly; } @@ -652,7 +652,7 @@ public string RuntimeVersion /// Gets or sets the contents of the native Win32 resources data directory of the underlying /// portable executable (PE) file. /// - public IResourceDirectory? NativeResourceDirectory + public ResourceDirectory? NativeResourceDirectory { get => _nativeResources.GetValue(this); set => _nativeResources.SetValue(value); @@ -1185,7 +1185,7 @@ protected virtual IList GetCustomAttributes() => /// /// This method is called upon initialization of the property. /// - protected virtual IResourceDirectory? GetNativeResources() => null; + protected virtual ResourceDirectory? GetNativeResources() => null; /// /// Obtains the native debug data directory of the underlying PE image (if available). diff --git a/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs b/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs index e755a2234..472f51bbe 100644 --- a/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs +++ b/src/AsmResolver.DotNet/Serialized/SerializedModuleDefinition.cs @@ -314,7 +314,7 @@ protected override IList GetExportedTypes() } /// - protected override IResourceDirectory? GetNativeResources() => ReaderContext.Image.Resources; + protected override ResourceDirectory? GetNativeResources() => ReaderContext.Image.Resources; /// protected override IList GetDebugData() => new List(ReaderContext.Image.DebugData); diff --git a/src/AsmResolver.PE.Win32Resources/IWin32Resource.cs b/src/AsmResolver.PE.Win32Resources/IWin32Resource.cs index f81bd4797..02c2fd49e 100644 --- a/src/AsmResolver.PE.Win32Resources/IWin32Resource.cs +++ b/src/AsmResolver.PE.Win32Resources/IWin32Resource.cs @@ -10,6 +10,6 @@ public interface IWin32Resource /// Serializes the win32 resource to the provided root win32 resource data directory. /// /// The root directory to submit the changes to. - void InsertIntoDirectory(IResourceDirectory rootDirectory); + void InsertIntoDirectory(ResourceDirectory rootDirectory); } } diff --git a/src/AsmResolver.PE.Win32Resources/Icon/IconGroupDirectory.cs b/src/AsmResolver.PE.Win32Resources/Icon/IconGroupDirectory.cs index 342ec0185..6f89417e0 100644 --- a/src/AsmResolver.PE.Win32Resources/Icon/IconGroupDirectory.cs +++ b/src/AsmResolver.PE.Win32Resources/Icon/IconGroupDirectory.cs @@ -21,7 +21,7 @@ public class IconGroupDirectory : SegmentBase /// The reader. /// The icon resource directory used to extract associated icon entries from. /// The icon group directory. - public static IconGroupDirectory FromReader(ref BinaryStreamReader reader, IResourceDirectory iconResourceDirectory) + public static IconGroupDirectory FromReader(ref BinaryStreamReader reader, ResourceDirectory iconResourceDirectory) { var result = new IconGroupDirectory { @@ -41,19 +41,19 @@ public static IconGroupDirectory FromReader(ref BinaryStreamReader reader, IReso return result; } - private static (IconGroupDirectoryEntry, IconEntry) ReadNextEntry(ref BinaryStreamReader reader, IResourceDirectory iconResourceDirectory) + private static (IconGroupDirectoryEntry, IconEntry) ReadNextEntry(ref BinaryStreamReader reader, ResourceDirectory iconResourceDirectory) { var entry = IconGroupDirectoryEntry.FromReader(ref reader); // search for icon reference in icon resource directory var iconDirectory = iconResourceDirectory .Entries - .OfType() + .OfType() .FirstOrDefault(d => d.Id == entry.Id); - var iconDataEntry = iconDirectory - ?.Entries - .OfType() + var iconDataEntry = iconDirectory? + .Entries + .OfType() .FirstOrDefault(); if (iconDataEntry is null) diff --git a/src/AsmResolver.PE.Win32Resources/Icon/IconResource.cs b/src/AsmResolver.PE.Win32Resources/Icon/IconResource.cs index 50c07b610..077b15db6 100644 --- a/src/AsmResolver.PE.Win32Resources/Icon/IconResource.cs +++ b/src/AsmResolver.PE.Win32Resources/Icon/IconResource.cs @@ -12,7 +12,7 @@ public class IconResource : IWin32Resource /// /// Used to keep track of icon groups. /// - private readonly Dictionary _entries = new Dictionary(); + private readonly Dictionary _entries = new(); /// /// Obtains the icon group resources from the provided root win32 resources directory. @@ -20,7 +20,7 @@ public class IconResource : IWin32Resource /// The root resources directory to extract the icon group from. /// The icon group resources, or null if none was found. /// Occurs when the resource data is not readable. - public static IconResource? FromDirectory(IResourceDirectory rootDirectory) + public static IconResource? FromDirectory(ResourceDirectory rootDirectory) { if (!rootDirectory.TryGetDirectory(ResourceType.GroupIcon, out var groupIconDirectory) || !rootDirectory.TryGetDirectory(ResourceType.Icon, out var iconDirectory)) @@ -30,11 +30,11 @@ public class IconResource : IWin32Resource var result = new IconResource(); - foreach (var iconGroupResource in groupIconDirectory.Entries.OfType()) + foreach (var iconGroupResource in groupIconDirectory.Entries.OfType()) { var dataEntry = iconGroupResource .Entries - .OfType() + .OfType() .FirstOrDefault(); if (dataEntry is null) @@ -81,7 +81,7 @@ public IconGroupDirectory this[uint id] public IEnumerable GetIconGroups() => _entries.Values; /// - public void InsertIntoDirectory(IResourceDirectory rootDirectory) + public void InsertIntoDirectory(ResourceDirectory rootDirectory) { // Construct new directory. var newGroupIconDirectory = new ResourceDirectory(ResourceType.GroupIcon); diff --git a/src/AsmResolver.PE.Win32Resources/Version/VersionInfoResource.cs b/src/AsmResolver.PE.Win32Resources/Version/VersionInfoResource.cs index 156370642..caa861561 100644 --- a/src/AsmResolver.PE.Win32Resources/Version/VersionInfoResource.cs +++ b/src/AsmResolver.PE.Win32Resources/Version/VersionInfoResource.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using AsmResolver.IO; @@ -74,21 +73,21 @@ public VersionTableEntry this[string name] /// /// The root resources directory to extract the version info from. /// The version info resource, or null if none was found. - public static IEnumerable FindAllFromDirectory(IResourceDirectory rootDirectory) + public static IEnumerable FindAllFromDirectory(ResourceDirectory rootDirectory) { if (!rootDirectory.TryGetDirectory(ResourceType.Version, out var versionDirectory)) return Enumerable.Empty(); var categoryDirectory = versionDirectory .Entries - .OfType() + .OfType() .FirstOrDefault(); if (categoryDirectory is null) return Enumerable.Empty(); return categoryDirectory.Entries - .OfType() + .OfType() .Select(FromResourceData)!; } @@ -97,7 +96,7 @@ public VersionTableEntry this[string name] /// /// The root resources directory to extract the version info from. /// The version info resource, or null if none was found. - public static VersionInfoResource? FromDirectory(IResourceDirectory rootDirectory) + public static VersionInfoResource? FromDirectory(ResourceDirectory rootDirectory) { return FindAllFromDirectory(rootDirectory).FirstOrDefault(); } @@ -108,19 +107,19 @@ public VersionTableEntry this[string name] /// The root resources directory to extract the version info from. /// The language identifier to get the version info from. /// The version info resource, or null if none was found. - public static VersionInfoResource? FromDirectory(IResourceDirectory rootDirectory, int lcid) + public static VersionInfoResource? FromDirectory(ResourceDirectory rootDirectory, int lcid) { if (!rootDirectory.TryGetDirectory(ResourceType.Version, out var versionDirectory)) return null; var categoryDirectory = versionDirectory .Entries - .OfType() + .OfType() .FirstOrDefault(); var dataEntry = categoryDirectory ?.Entries - .OfType() + .OfType() .FirstOrDefault(x => x.Id == lcid); if (dataEntry is null) @@ -134,7 +133,7 @@ public VersionTableEntry this[string name] /// /// The data entry to extract the version info from. /// The extracted version info resource. - public static VersionInfoResource FromResourceData(IResourceData dataEntry) + public static VersionInfoResource FromResourceData(ResourceData dataEntry) { if (dataEntry.CanRead) { @@ -271,7 +270,7 @@ protected override void WriteValue(IBinaryStreamWriter writer) } /// - public void InsertIntoDirectory(IResourceDirectory rootDirectory) + public void InsertIntoDirectory(ResourceDirectory rootDirectory) { // Add version directory if it doesn't exist yet. if (!rootDirectory.TryGetDirectory(ResourceType.Version, out var versionDirectory)) diff --git a/src/AsmResolver.PE/PEImage.cs b/src/AsmResolver.PE/PEImage.cs index 61b050224..420c0fa91 100644 --- a/src/AsmResolver.PE/PEImage.cs +++ b/src/AsmResolver.PE/PEImage.cs @@ -23,7 +23,7 @@ public class PEImage { private IList? _imports; private readonly LazyVariable _exports; - private readonly LazyVariable _resources; + private readonly LazyVariable _resources; private readonly LazyVariable _exceptions; private IList? _relocations; private readonly LazyVariable _dotNetDirectory; @@ -181,7 +181,7 @@ public static PEImage FromFile(PEFile peFile, PEReaderParameters readerParameter public PEImage() { _exports = new LazyVariable(x => x.GetExports()); - _resources = new LazyVariable(x => x.GetResources()); + _resources = new LazyVariable(x => x.GetResources()); _exceptions = new LazyVariable(x => x.GetExceptions()); _dotNetDirectory = new LazyVariable(x => x.GetDotNetDirectory()); _tlsDirectory = new LazyVariable(x => x.GetTlsDirectory()); @@ -323,7 +323,7 @@ public ExportDirectory? Exports /// /// Gets or sets the root resource directory in the PE, if available. /// - public IResourceDirectory? Resources + public ResourceDirectory? Resources { get => _resources.GetValue(this); set => _resources.SetValue(value); @@ -427,7 +427,7 @@ public CertificateCollection Certificates /// /// This method is called upon initialization of the property. /// - protected virtual IResourceDirectory? GetResources() => null; + protected virtual ResourceDirectory? GetResources() => null; /// /// Obtains the contents of the exceptions data directory in the PE. diff --git a/src/AsmResolver.PE/SerializedPEImage.cs b/src/AsmResolver.PE/SerializedPEImage.cs index 8dd4941f8..95b04699f 100644 --- a/src/AsmResolver.PE/SerializedPEImage.cs +++ b/src/AsmResolver.PE/SerializedPEImage.cs @@ -76,7 +76,7 @@ protected override IList GetImports() } /// - protected override IResourceDirectory? GetResources() + protected override ResourceDirectory? GetResources() { var dataDirectory = PEFile.OptionalHeader.GetDataDirectory(DataDirectoryIndex.ResourceDirectory); if (!dataDirectory.IsPresentInPE || !PEFile.TryCreateDataDirectoryReader(dataDirectory, out var reader)) diff --git a/src/AsmResolver.PE/Win32Resources/Builder/ResourceDataTableBuffer.cs b/src/AsmResolver.PE/Win32Resources/Builder/ResourceDataTableBuffer.cs index 76b88e15e..bfeb45d72 100644 --- a/src/AsmResolver.PE/Win32Resources/Builder/ResourceDataTableBuffer.cs +++ b/src/AsmResolver.PE/Win32Resources/Builder/ResourceDataTableBuffer.cs @@ -5,7 +5,7 @@ namespace AsmResolver.PE.Win32Resources.Builder /// /// Provides a mechanism for building a table of data entries in a resource directory. /// - public class ResourceDataTableBuffer : ResourceTableBuffer + public class ResourceDataTableBuffer : ResourceTableBuffer { /// /// Creates a new data table buffer. @@ -17,7 +17,7 @@ public ResourceDataTableBuffer(ISegment parentBuffer) } /// - public override uint GetEntrySize(IResourceData entry) => SerializedResourceData.ResourceDataEntrySize; + public override uint GetEntrySize(ResourceData entry) => SerializedResourceData.ResourceDataEntrySize; /// public override void Write(IBinaryStreamWriter writer) @@ -26,7 +26,7 @@ public override void Write(IBinaryStreamWriter writer) WriteDataEntry(writer, Entries[i]); } - private static void WriteDataEntry(IBinaryStreamWriter writer, IResourceData entry) + private static void WriteDataEntry(IBinaryStreamWriter writer, ResourceData entry) { if (entry.Contents is null) { diff --git a/src/AsmResolver.PE/Win32Resources/Builder/ResourceDirectoryBuffer.cs b/src/AsmResolver.PE/Win32Resources/Builder/ResourceDirectoryBuffer.cs index 6b651e0e2..7314ea401 100644 --- a/src/AsmResolver.PE/Win32Resources/Builder/ResourceDirectoryBuffer.cs +++ b/src/AsmResolver.PE/Win32Resources/Builder/ResourceDirectoryBuffer.cs @@ -41,7 +41,7 @@ public ResourceDirectoryBuffer() /// /// Gets the segment containing the table with all directory entries. /// - public ResourceTableBuffer DirectoryTable + public ResourceTableBuffer DirectoryTable { get; } @@ -49,7 +49,7 @@ public ResourceTableBuffer DirectoryTable /// /// Gets the segment containing the table with all data entries. /// - public ResourceTableBuffer DataEntryTable + public ResourceTableBuffer DataEntryTable { get; } @@ -79,7 +79,7 @@ public SegmentBuilder DataTable /// Adds a resource directory and all its sub entries to the buffer. /// /// The directory to add. - public void AddDirectory(IResourceDirectory directory) + public void AddDirectory(ResourceDirectory directory) { DirectoryTable.AddEntry(directory); if (directory.Name != null) @@ -92,7 +92,7 @@ public void AddDirectory(IResourceDirectory directory) private void AddEntry(IResourceEntry entry) { if (entry.IsDirectory) - AddDirectory((IResourceDirectory) entry); + AddDirectory((ResourceDirectory) entry); else if (entry.IsData) AddDataEntry(entry); else @@ -101,7 +101,7 @@ private void AddEntry(IResourceEntry entry) private void AddDataEntry(IResourceEntry entry) { - var data = (IResourceData) entry; + var data = (ResourceData) entry; DataEntryTable.AddEntry(data); if (data.Contents is not null) diff --git a/src/AsmResolver.PE/Win32Resources/Builder/ResourceDirectoryTableBuffer.cs b/src/AsmResolver.PE/Win32Resources/Builder/ResourceDirectoryTableBuffer.cs index db45b1cf7..9f8caca8b 100644 --- a/src/AsmResolver.PE/Win32Resources/Builder/ResourceDirectoryTableBuffer.cs +++ b/src/AsmResolver.PE/Win32Resources/Builder/ResourceDirectoryTableBuffer.cs @@ -7,10 +7,10 @@ namespace AsmResolver.PE.Win32Resources.Builder /// /// Provides a mechanism for building a table of directory entries in a resource directory. /// - public class ResourceDirectoryTableBuffer : ResourceTableBuffer + public class ResourceDirectoryTableBuffer : ResourceTableBuffer { private readonly ResourceTableBuffer _nameTable; - private readonly ResourceTableBuffer _dataEntryTable; + private readonly ResourceTableBuffer _dataEntryTable; /// /// Creates a new resource directory table buffer. @@ -21,7 +21,7 @@ public class ResourceDirectoryTableBuffer : ResourceTableBuffer nameTable, - ResourceTableBuffer dataEntryTable) + ResourceTableBuffer dataEntryTable) : base(parentBuffer) { _nameTable = nameTable ?? throw new ArgumentNullException(nameof(nameTable)); @@ -29,7 +29,7 @@ public ResourceDirectoryTableBuffer( } /// - public override uint GetEntrySize(IResourceDirectory entry) => + public override uint GetEntrySize(ResourceDirectory entry) => SerializedResourceDirectory.ResourceDirectorySize + (uint) entry.Entries.Count * ResourceDirectoryEntry.EntrySize; @@ -37,15 +37,10 @@ public override uint GetEntrySize(IResourceDirectory entry) => public override void Write(IBinaryStreamWriter writer) { foreach (var entry in Entries) - { - if (entry.IsDirectory) - WriteDirectory(writer, (IResourceDirectory) entry); - else - throw new ArgumentException("Directory table contains a data entry."); - } + WriteDirectory(writer, entry); } - private void WriteDirectory(IBinaryStreamWriter writer, IResourceDirectory directory) + private void WriteDirectory(IBinaryStreamWriter writer, ResourceDirectory directory) { ushort namedEntries = (ushort) directory.Entries.Count(e => e.Name != null); ushort idEntries = (ushort) (directory.Entries.Count - namedEntries); @@ -68,8 +63,8 @@ private void WriteEntry(IBinaryStreamWriter writer, IResourceEntry entry) : entry.Id); writer.WriteUInt32(entry.IsDirectory - ? (GetEntryOffset((IResourceDirectory) entry) | 0x8000_0000) - : _dataEntryTable.GetEntryOffset((IResourceData) entry)); + ? (GetEntryOffset((ResourceDirectory) entry) | 0x8000_0000) + : _dataEntryTable.GetEntryOffset((ResourceData) entry)); } } diff --git a/src/AsmResolver.PE/Win32Resources/IResourceData.cs b/src/AsmResolver.PE/Win32Resources/IResourceData.cs deleted file mode 100644 index b538448cd..000000000 --- a/src/AsmResolver.PE/Win32Resources/IResourceData.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using AsmResolver.IO; - -namespace AsmResolver.PE.Win32Resources -{ - /// - /// Represents a single data entry in a Win32 resource directory. - /// - public interface IResourceData : IResourceEntry - { - /// - /// Gets or sets the raw contents of the data entry. - /// - ISegment? Contents - { - get; - set; - } - - /// - /// Gets or sets the code page that is used to decode code point values within the resource data. - /// - /// - /// Typically, the code page would be the Unicode code page. - /// - uint CodePage - { - get; - set; - } - - /// - /// Gets a value indicating whether the is readable using a binary stream reader. - /// - [MemberNotNullWhen(true, nameof(Contents))] - bool CanRead - { - get; - } - - /// - /// Creates a new binary stream reader that reads the raw contents of the resource file. - /// - /// The reader. - BinaryStreamReader CreateReader(); - } -} diff --git a/src/AsmResolver.PE/Win32Resources/IResourceDirectory.cs b/src/AsmResolver.PE/Win32Resources/IResourceDirectory.cs deleted file mode 100644 index 9cf0e822d..000000000 --- a/src/AsmResolver.PE/Win32Resources/IResourceDirectory.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -namespace AsmResolver.PE.Win32Resources -{ - /// - /// Represents a single directory containing Win32 resources of a PE image. - /// - public interface IResourceDirectory : IResourceEntry - { - /// - /// Gets the type of resources stored in the directory. - /// - ResourceType Type - { - get; - } - - /// - /// Gets or sets the flags of the directory. - /// - /// - /// This field is reserved and is usually set to zero. - /// - uint Characteristics - { - get; - set; - } - - /// - /// Gets or sets the time that the resource data was created by the compiler. - /// - uint TimeDateStamp - { - get; - set; - } - - /// - /// Gets or sets the major version number of the directory. - /// - ushort MajorVersion - { - get; - set; - } - - /// - /// Gets or sets the minor version number of the directory. - /// - ushort MinorVersion - { - get; - set; - } - - /// - /// Gets a collection of entries that are stored in the directory. - /// - IList Entries - { - get; - } - - /// - /// Looks up an entry in the directory by its unique identifier. - /// - /// The identifier of the entry to lookup. - /// The entry. - /// - /// Occurs when no entry with the provided identifier was found. - /// - IResourceEntry GetEntry(uint id); - - /// - /// Looks up an directory by its unique identifier. - /// - /// The identifier of the directory to lookup. - /// The directory. - /// - /// Occurs when no directory with the provided identifier was found. - /// - IResourceDirectory GetDirectory(uint id); - - /// - /// Looks up an directory by its resource type. - /// - /// The type of resources to lookup. - /// The directory. - /// - /// Occurs when no directory with the provided identifier was found. - /// - IResourceDirectory GetDirectory(ResourceType type); - - /// - /// Looks up a data entry in the directory by its unique identifier. - /// - /// The id of the data entry to lookup. - /// The data entry. - /// - /// Occurs when no data entry with the provided identifier was found. - /// - IResourceData GetData(uint id); - - /// - /// Attempts to looks up an entry in the directory by its unique identifier. - /// - /// The identifier of the entry to lookup. - /// The found entry, or null if none was found. - /// true if the entry was found, false otherwise. - bool TryGetEntry(uint id, [NotNullWhen(true)] out IResourceEntry? entry); - - /// - /// Attempts to looks up a directory by its unique identifier. - /// - /// The identifier of the directory to lookup. - /// The found directory, or null if none was found. - /// true if the directory was found, false otherwise. - bool TryGetDirectory(uint id, [NotNullWhen(true)] out IResourceDirectory? directory); - - /// - /// Attempts to looks up a directory by its resource type. - /// - /// The type of resources to lookup. - /// The found directory, or null if none was found. - /// true if the directory was found, false otherwise. - bool TryGetDirectory(ResourceType type, [NotNullWhen(true)] out IResourceDirectory? directory); - - /// - /// Attempts to looks up a data entry in the directory by its unique identifier. - /// - /// The identifier of the data entry to lookup. - /// The found data entry, or null if none was found. - /// true if the data entry was found, false otherwise. - bool TryGetData(uint id, [NotNullWhen(true)] out IResourceData? data); - - /// - /// Replaces an existing entry with the same ID with the provided entry, or inserts the new entry into the directory. - /// - /// The entry to store in the directory. - void InsertOrReplaceEntry(IResourceEntry entry); - - /// - /// Removes an entry in the directory by its unique identifier. - /// - /// The identifier of the entry to remove. - /// true if the data entry was found and removed, false otherwise. - bool RemoveEntry(uint id); - - /// - /// Removes a directory in the directory by its resource type. - /// - /// The type of resources to remove. - /// true if the directory was found and removed, false otherwise. - bool RemoveEntry(ResourceType type); - } -} diff --git a/src/AsmResolver.PE/Win32Resources/IResourceEntry.cs b/src/AsmResolver.PE/Win32Resources/IResourceEntry.cs index 3cd748839..67f091ef3 100644 --- a/src/AsmResolver.PE/Win32Resources/IResourceEntry.cs +++ b/src/AsmResolver.PE/Win32Resources/IResourceEntry.cs @@ -5,12 +5,12 @@ namespace AsmResolver.PE.Win32Resources /// /// Represents one entry in a win32 resource directory. /// - public interface IResourceEntry : IOwnedCollectionElement + public interface IResourceEntry : IOwnedCollectionElement { /// /// Gets the parent directory the entry is stored in. /// - IResourceDirectory? ParentDirectory + ResourceDirectory? ParentDirectory { get; } diff --git a/src/AsmResolver.PE/Win32Resources/ResourceData.cs b/src/AsmResolver.PE/Win32Resources/ResourceData.cs index c6659539d..377075264 100644 --- a/src/AsmResolver.PE/Win32Resources/ResourceData.cs +++ b/src/AsmResolver.PE/Win32Resources/ResourceData.cs @@ -1,13 +1,14 @@ using System; +using System.Diagnostics.CodeAnalysis; using AsmResolver.Collections; using AsmResolver.IO; namespace AsmResolver.PE.Win32Resources { /// - /// Provides an implementation for a single data entry in a Win32 resource directory. + /// Represents a single data entry in a Win32 resource directory. /// - public class ResourceData : IResourceData + public class ResourceData : IResourceEntry { private readonly LazyVariable _contents; @@ -44,13 +45,13 @@ public ResourceData(uint id, ISegment contents) } /// - public IResourceDirectory? ParentDirectory + public ResourceDirectory? ParentDirectory { get; private set; } - IResourceDirectory? IOwnedCollectionElement.Owner + ResourceDirectory? IOwnedCollectionElement.Owner { get => ParentDirectory; set => ParentDirectory = value; @@ -76,24 +77,37 @@ public uint Id /// bool IResourceEntry.IsData => true; - /// + /// + /// Gets or sets the raw contents of the data entry. + /// public ISegment? Contents { get => _contents.GetValue(this); set => _contents.SetValue(value); } - /// + /// + /// Gets or sets the code page that is used to decode code point values within the resource data. + /// + /// + /// Typically, the code page would be the Unicode code page. + /// public uint CodePage { get; set; } - /// + /// + /// Gets a value indicating whether the is readable using a binary stream reader. + /// + [MemberNotNullWhen(true, nameof(Contents))] public bool CanRead => Contents is IReadableSegment; - /// + /// + /// Creates a new binary stream reader that reads the raw contents of the resource file. + /// + /// The reader. public BinaryStreamReader CreateReader() { return Contents is IReadableSegment readableSegment diff --git a/src/AsmResolver.PE/Win32Resources/ResourceDirectory.cs b/src/AsmResolver.PE/Win32Resources/ResourceDirectory.cs index 18e378161..3f2ea3825 100644 --- a/src/AsmResolver.PE/Win32Resources/ResourceDirectory.cs +++ b/src/AsmResolver.PE/Win32Resources/ResourceDirectory.cs @@ -7,10 +7,9 @@ namespace AsmResolver.PE.Win32Resources { /// - /// Provides a basic implementation of a resource directory that can be initialized and added to another resource - /// directory or used as a root resource directory of a PE image. + /// Represents a single directory containing Win32 resources of a PE image. /// - public class ResourceDirectory : IResourceDirectory + public class ResourceDirectory : IResourceEntry { private IList? _entries; @@ -49,13 +48,13 @@ public ResourceDirectory(ResourceType type) } /// - public IResourceDirectory? ParentDirectory + public ResourceDirectory? ParentDirectory { get; private set; } - IResourceDirectory? IOwnedCollectionElement.Owner + ResourceDirectory? IOwnedCollectionElement.Owner { get => ParentDirectory; set => ParentDirectory = value; @@ -81,42 +80,57 @@ public uint Id /// bool IResourceEntry.IsData => false; - /// + /// + /// Gets the type of resources stored in the directory. + /// public ResourceType Type { get => (ResourceType) Id; set => Id = (uint) value; } - /// + /// + /// Gets or sets the flags of the directory. + /// + /// + /// This field is reserved and is usually set to zero. + /// public uint Characteristics { get; set; } - /// + /// + /// Gets or sets the time that the resource data was created by the compiler. + /// public uint TimeDateStamp { get; set; } - /// + /// + /// Gets or sets the major version number of the directory. + /// public ushort MajorVersion { get; set; } - /// + /// + /// Gets or sets the minor version number of the directory. + /// public ushort MinorVersion { get; set; } - /// + /// + /// Gets a collection of entries that are stored in the directory. + /// public IList Entries { get @@ -149,7 +163,14 @@ private bool TryGetEntryIndex(uint id, out int index) return false; } - /// + /// + /// Looks up an entry in the directory by its unique identifier. + /// + /// The identifier of the entry to lookup. + /// The entry. + /// + /// Occurs when no entry with the provided identifier was found. + /// public IResourceEntry GetEntry(uint id) { if (!TryGetEntry(id, out var entry)) @@ -157,31 +178,57 @@ public IResourceEntry GetEntry(uint id) return entry; } - /// - public IResourceDirectory GetDirectory(uint id) + /// + /// Looks up an directory by its unique identifier. + /// + /// The identifier of the directory to lookup. + /// The directory. + /// + /// Occurs when no directory with the provided identifier was found. + /// + public ResourceDirectory GetDirectory(uint id) { if (!TryGetDirectory(id, out var directory)) throw new KeyNotFoundException($"Directory does not contain a directory with id {id}."); return directory; } - /// - public IResourceDirectory GetDirectory(ResourceType type) + /// + /// Looks up an directory by its resource type. + /// + /// The type of resources to lookup. + /// The directory. + /// + /// Occurs when no directory with the provided identifier was found. + /// + public ResourceDirectory GetDirectory(ResourceType type) { if (!TryGetDirectory(type, out var directory)) throw new KeyNotFoundException($"Directory does not contain a directory of type {type}."); return directory; } - /// - public IResourceData GetData(uint id) + /// + /// Looks up a data entry in the directory by its unique identifier. + /// + /// The id of the data entry to lookup. + /// The data entry. + /// + /// Occurs when no data entry with the provided identifier was found. + /// + public ResourceData GetData(uint id) { if (!TryGetData(id, out var data)) throw new KeyNotFoundException($"Directory does not contain a data entry with id {id}."); return data; } - /// + /// + /// Attempts to looks up an entry in the directory by its unique identifier. + /// + /// The identifier of the entry to lookup. + /// The found entry, or null if none was found. + /// true if the entry was found, false otherwise. public bool TryGetEntry(uint id, [NotNullWhen(true)] out IResourceEntry? entry) { if (!TryGetEntryIndex(id, out int index)) @@ -194,12 +241,17 @@ public bool TryGetEntry(uint id, [NotNullWhen(true)] out IResourceEntry? entry) return true; } - /// - public bool TryGetDirectory(uint id, [NotNullWhen(true)] out IResourceDirectory? directory) + /// + /// Attempts to looks up a directory by its unique identifier. + /// + /// The identifier of the directory to lookup. + /// The found directory, or null if none was found. + /// true if the directory was found, false otherwise. + public bool TryGetDirectory(uint id, [NotNullWhen(true)] out ResourceDirectory? directory) { if (TryGetEntry(id, out var entry) && entry.IsDirectory) { - directory = (IResourceDirectory) entry; + directory = (ResourceDirectory) entry; return true; } @@ -207,16 +259,26 @@ public bool TryGetDirectory(uint id, [NotNullWhen(true)] out IResourceDirectory? return false; } - /// - public bool TryGetDirectory(ResourceType type, [NotNullWhen(true)] out IResourceDirectory? directory) => + /// + /// Attempts to looks up a directory by its resource type. + /// + /// The type of resources to lookup. + /// The found directory, or null if none was found. + /// true if the directory was found, false otherwise. + public bool TryGetDirectory(ResourceType type, [NotNullWhen(true)] out ResourceDirectory? directory) => TryGetDirectory((uint) type, out directory); - /// - public bool TryGetData(uint id, [NotNullWhen(true)] out IResourceData? data) + /// + /// Attempts to looks up a data entry in the directory by its unique identifier. + /// + /// The identifier of the data entry to lookup. + /// The found data entry, or null if none was found. + /// true if the data entry was found, false otherwise. + public bool TryGetData(uint id, [NotNullWhen(true)] out ResourceData? data) { if (TryGetEntry(id, out var entry) && entry.IsData) { - data = (IResourceData) entry; + data = (ResourceData) entry; return true; } @@ -224,7 +286,10 @@ public bool TryGetData(uint id, [NotNullWhen(true)] out IResourceData? data) return false; } - /// + /// + /// Replaces an existing entry with the same ID with the provided entry, or inserts the new entry into the directory. + /// + /// The entry to store in the directory. public void InsertOrReplaceEntry(IResourceEntry entry) { if (TryGetEntryIndex(entry.Id, out int index)) @@ -233,7 +298,11 @@ public void InsertOrReplaceEntry(IResourceEntry entry) Entries.Insert(index, entry); } - /// + /// + /// Removes an entry in the directory by its unique identifier. + /// + /// The identifier of the entry to remove. + /// true if the data entry was found and removed, false otherwise. public bool RemoveEntry(uint id) { if (!TryGetEntryIndex(id, out int index)) @@ -243,7 +312,11 @@ public bool RemoveEntry(uint id) return true; } - /// + /// + /// Removes a directory in the directory by its resource type. + /// + /// The type of resources to remove. + /// true if the directory was found and removed, false otherwise. public bool RemoveEntry(ResourceType type) => RemoveEntry((uint) type); /// @@ -254,7 +327,7 @@ public bool RemoveEntry(uint id) /// This method is called upon initialization of the property. /// protected virtual IList GetEntries() => - new OwnedCollection(this); + new OwnedCollection(this); /// public override string ToString() => $"Directory ({Name ?? Id.ToString()})"; diff --git a/src/AsmResolver.PE/Win32Resources/SerializedResourceDirectory.cs b/src/AsmResolver.PE/Win32Resources/SerializedResourceDirectory.cs index a326aeba8..e4506bcd5 100644 --- a/src/AsmResolver.PE/Win32Resources/SerializedResourceDirectory.cs +++ b/src/AsmResolver.PE/Win32Resources/SerializedResourceDirectory.cs @@ -72,7 +72,7 @@ public SerializedResourceDirectory(PEReaderContext context, ResourceDirectoryEnt /// protected override IList GetEntries() { - var result = new OwnedCollection(this); + var result = new OwnedCollection(this); // Optimisation, check for invalid resource directory offset, and prevention of self loop: if (_namedEntries + _idEntries == 0 || _depth >= MaxDepth) diff --git a/test/AsmResolver.DotNet.Tests/ModuleDefinitionTest.cs b/test/AsmResolver.DotNet.Tests/ModuleDefinitionTest.cs index c267d991a..b2e7f7eee 100644 --- a/test/AsmResolver.DotNet.Tests/ModuleDefinitionTest.cs +++ b/test/AsmResolver.DotNet.Tests/ModuleDefinitionTest.cs @@ -386,7 +386,7 @@ public void PersistentResources() } } }; - module.NativeResourceDirectory.Entries.Add(directory); + module.NativeResourceDirectory!.Entries.Add(directory); // Write and rebuild. using var stream = new MemoryStream(); @@ -394,12 +394,12 @@ public void PersistentResources() var newModule = ModuleDefinition.FromReader(new BinaryStreamReader(stream.ToArray())); // Assert contents. - var newDirectory = (IResourceDirectory)newModule.NativeResourceDirectory.Entries + var newDirectory = (ResourceDirectory) newModule.NativeResourceDirectory!.Entries .First(entry => entry.Name == directoryName); - newDirectory = (IResourceDirectory)newDirectory.Entries[0]; + newDirectory = (ResourceDirectory)newDirectory.Entries[0]; - var newData = (IResourceData)newDirectory.Entries[0]; - var newContents = (IReadableSegment)newData.Contents; + var newData = (ResourceData)newDirectory.Entries[0]; + var newContents = (IReadableSegment)newData.Contents!; Assert.Equal(entryData, newContents.ToArray()); } diff --git a/test/AsmResolver.PE.Tests/Win32Resources/ResourceDirectoryTest.cs b/test/AsmResolver.PE.Tests/Win32Resources/ResourceDirectoryTest.cs index b443ea97e..aa77b3e88 100644 --- a/test/AsmResolver.PE.Tests/Win32Resources/ResourceDirectoryTest.cs +++ b/test/AsmResolver.PE.Tests/Win32Resources/ResourceDirectoryTest.cs @@ -42,12 +42,12 @@ private void AssertStructure(ResourceEntryInfo expectedStructure, IResourceEntry if (expected.IsData) { - Assert.IsAssignableFrom(current); + Assert.IsAssignableFrom(current); } else { - Assert.IsAssignableFrom(current); - var subEntries = ((IResourceDirectory) current).Entries; + Assert.IsAssignableFrom(current); + var subEntries = ((ResourceDirectory) current).Entries; Assert.Equal(expected.Entries.Count, subEntries.Count); for (int i = 0; i < subEntries.Count; i++) @@ -120,7 +120,7 @@ public void MaliciousSelfLoop() Assert.True(dirCount < maxDirCount, "Traversal reached limit of resource directories."); dirCount++; - foreach (var entry in ((IResourceDirectory) current).Entries) + foreach (var entry in ((ResourceDirectory) current).Entries) stack.Push(entry); } } @@ -144,7 +144,7 @@ public void MaliciousDirectoryOffset() Assert.Equal(16u, entry.Id); Assert.True(entry.IsDirectory); - var directory = (IResourceDirectory) entry; + var directory = (ResourceDirectory) entry; Assert.Empty(directory.Entries); } @@ -154,9 +154,9 @@ public void MaliciousDataOffset() var peImage = PEImage.FromBytes(Properties.Resources.HelloWorld_MaliciousWin32ResDataOffset, new PEReaderParameters(EmptyErrorListener.Instance)); - var directory = (IResourceDirectory) peImage.Resources!.Entries[0]; - directory = (IResourceDirectory) directory.Entries[0]; - var data = (IResourceData) directory.Entries[0]; + var directory = (ResourceDirectory) peImage.Resources!.Entries[0]; + directory = (ResourceDirectory) directory.Entries[0]; + var data = (ResourceData) directory.Entries[0]; Assert.Null(data.Contents); } From 79b7a0145d9a18e0b47b6ad6ecc50378342a9758 Mon Sep 17 00:00:00 2001 From: Washi Date: Tue, 4 Jun 2024 00:28:18 +0200 Subject: [PATCH 8/8] Update docs. --- docs/guides/dotnet/advanced-module-reading.md | 2 +- docs/guides/dotnet/basics.md | 6 +++--- docs/guides/dotnet/bundles.md | 2 +- docs/guides/dotnet/index.md | 2 +- docs/guides/peimage/basics.md | 2 +- docs/guides/peimage/debug.md | 2 +- docs/guides/peimage/dotnet.md | 18 +++++++++--------- docs/guides/peimage/exceptions.md | 2 +- docs/guides/peimage/exports.md | 4 ++-- docs/guides/peimage/imports.md | 10 +++++----- docs/guides/peimage/index.md | 8 ++++---- docs/guides/peimage/ready-to-run.md | 2 +- docs/guides/peimage/tls.md | 2 +- docs/guides/peimage/win32resources.md | 16 ++++++++-------- 14 files changed, 39 insertions(+), 39 deletions(-) diff --git a/docs/guides/dotnet/advanced-module-reading.md b/docs/guides/dotnet/advanced-module-reading.md index 959509b4a..e5e18cdf7 100644 --- a/docs/guides/dotnet/advanced-module-reading.md +++ b/docs/guides/dotnet/advanced-module-reading.md @@ -154,7 +154,7 @@ public class CustomFieldRvaDataReader : FieldRvaDataReader public override ISegment ResolveFieldData( IErrorListener listener, Platform platform, - IDotNetDirectory directory, + DotNetDirectory directory, in FieldRvaRow fieldRvaRow) { // ... diff --git a/docs/guides/dotnet/basics.md b/docs/guides/dotnet/basics.md index 3e145a98a..f90d76f0f 100644 --- a/docs/guides/dotnet/basics.md +++ b/docs/guides/dotnet/basics.md @@ -61,7 +61,7 @@ var module = ModuleDefinition.FromReader(reader); ``` ``` csharp -IPEImage peImage = ... +PEImage peImage = ... var module = ModuleDefinition.FromImage(peImage); ``` @@ -131,7 +131,7 @@ var assembly = AssemblyDefinition.FromFile(@"C:\myfile.exe"); ``` ``` csharp -IPEFile peFile = ... +PEFile peFile = ... var assembly = AssemblyDefinition.FromFile(peFile); ``` @@ -141,7 +141,7 @@ var assembly = AssemblyDefinition.FromReader(reader); ``` ``` csharp -IPEImage peImage = ... +PEImage peImage = ... var assembly = AssemblyDefinition.FromImage(peImage); ``` diff --git a/docs/guides/dotnet/bundles.md b/docs/guides/dotnet/bundles.md index 3e2e4da49..ab29fe68a 100644 --- a/docs/guides/dotnet/bundles.md +++ b/docs/guides/dotnet/bundles.md @@ -153,7 +153,7 @@ manifest.WriteUsingTemplate( > [!NOTE] > `BundleManifest` and `BundlerParameters` also define overloads of the > `WriteUsingTemplate` and `FromTemplate` / `FromExistingBundle` -> respectively, taking `byte[]`, `IDataSource` or `IPEImage` instances +> respectively, taking `byte[]`, `IDataSource` or `PEImage` instances > instead of file paths. diff --git a/docs/guides/dotnet/index.md b/docs/guides/dotnet/index.md index b509b82c6..d7b6afc3e 100644 --- a/docs/guides/dotnet/index.md +++ b/docs/guides/dotnet/index.md @@ -17,6 +17,6 @@ In short, this means the following: The third layer of abstraction is the highest level of abstraction for a .NET assembly that AsmResolver provides. All objects exposed by this -layer are completely mutable and can be serialized back to a `IPEImage` +layer are completely mutable and can be serialized back to a `PEImage` from the second layer, to a `PEFile` from the first layer, or to the disk. diff --git a/docs/guides/peimage/basics.md b/docs/guides/peimage/basics.md index bf67ad95a..189af5d88 100644 --- a/docs/guides/peimage/basics.md +++ b/docs/guides/peimage/basics.md @@ -30,7 +30,7 @@ var peImage = PEImage.FromFile(@"C:\myfile.exe"); ``` ``` csharp -IPEFile peFile = ... +PEFile peFile = ... var peImage = PEImage.FromFile(peFile); ``` diff --git a/docs/guides/peimage/debug.md b/docs/guides/peimage/debug.md index a29f82d8c..8c4a59f91 100644 --- a/docs/guides/peimage/debug.md +++ b/docs/guides/peimage/debug.md @@ -13,7 +13,7 @@ using AsmResolver.PE.Debug; ## The Debug Data Entries -The `IPEImage` exposes all debug information through the `DebugData` +The `PEImage` class exposes all debug information through the `DebugData` property. This is a list of `DebugDataEntry`, providing access to the type of debug data, as well as the version and raw contents of the data that is stored. diff --git a/docs/guides/peimage/dotnet.md b/docs/guides/peimage/dotnet.md index 6ec04d65e..4ab6b4737 100644 --- a/docs/guides/peimage/dotnet.md +++ b/docs/guides/peimage/dotnet.md @@ -11,10 +11,10 @@ applications. ## .NET directory / CLR 2.0 header The .NET data directory can be accessed by the -`IPEImage.DotNetDirectory` property. +`PEImage.DotNetDirectory` property. ``` csharp -IPEImage peImage = ... +PEImage peImage = ... Console.WriteLine($"Managed entry point: {peImage.DotNetDirectory.EntryPoint}"); ``` @@ -26,9 +26,9 @@ that is referenced by the .NET directory. It contains the metadata streams, such as the table and the blob stream, which play a key role in the execution of a .NET binary. -To access the metadata directory, access the `IDotNetDirectory.Metadata` -property, which will provide you an instance of the `IMetadata` -interface: +To access the metadata directory, access the `DotNetDirectory.Metadata` +property, which will provide you an instance of the `MetadataDirectory` +class: ``` csharp var metadata = peImage.DotNetDirectory.Metadata; @@ -39,7 +39,7 @@ Console.WriteLine($"Target .NET runtime version: {metadata.VersionString}"); ## Metadata streams -The `IMetadata` interface also exposes the `Streams` property, a list of +The `MetadataDirectory` class also exposes the `Streams` property, a list of `IMetadataStream` instances. ``` csharp @@ -330,14 +330,14 @@ only uses one native symbol (either `mscoree.dll!_CorExeMain` or `mscoree.dll!_CorDllMain` ). AsmResolver includes a built-in implementation for this that is based on [the reference implementation provided by GData](https://www.gdatasoftware.com/blog/2020/06/36164-introducing-the-typerefhash-trh). The hash can be obtained using the `GetTypeReferenceHash` extension method on -`IPEImage`or on `IMetadata`: +`PEImage`or on `MetadataDirectory`: ``` csharp -IPEImage image = ... +PEImage image = ... byte[] hash = image.GetTypeReferenceHash(); ``` ``` csharp -IMetadata metadata = ... +MetadataDirectory metadata = ... byte[] hash = metadata.GetTypeReferenceHash(); ``` diff --git a/docs/guides/peimage/exceptions.md b/docs/guides/peimage/exceptions.md index b7459d536..3f65b6f00 100644 --- a/docs/guides/peimage/exceptions.md +++ b/docs/guides/peimage/exceptions.md @@ -15,7 +15,7 @@ using AsmResolver.PE.Exceptions; ## Runtime Functions -The `IPEImage` interface exposes these tables through the `Exceptions` +The `PEImage` class exposes these tables through the `Exceptions` property. This is of type `IExceptionsDirectory`, which allows for read access to instances of `IRuntimeFunction` through the `GetEntries` method. This interface models all the runtime functions through the diff --git a/docs/guides/peimage/exports.md b/docs/guides/peimage/exports.md index a00d3fb75..452651698 100644 --- a/docs/guides/peimage/exports.md +++ b/docs/guides/peimage/exports.md @@ -3,7 +3,7 @@ Dynamically linked libraries (DLLs) often expose symbols through defining exports in the exports directory. -The `IPEImage` interface exposes the `Exports` property, exposing a +The `PEImage` class exposes the `Exports` property, exposing a mutable instance of `ExportDirectory`, which defines the following properties: - `Name`: The name of the dynamically linked library. @@ -32,7 +32,7 @@ defines: ## Example Below is an example of a program that lists all symbols exported by a -given `IPEImage` instance: +given `PEImage` instance: ``` csharp foreach (var symbol in peImage.Exports.Entries) diff --git a/docs/guides/peimage/imports.md b/docs/guides/peimage/imports.md index a0699039b..3a6ca94eb 100644 --- a/docs/guides/peimage/imports.md +++ b/docs/guides/peimage/imports.md @@ -14,10 +14,10 @@ using AsmResolver.PE.Imports; ## Imported Modules and Symbols -The `IPEImage` interface exposes the `Imports` property, which contains +The `PEImage` class exposes the `Imports` property, which contains all members that are resolved at runtime, grouped by the defining module. Below an example of a program that lists all members imported by -a given `IPEImage` instance: +a given `PEImage` instance: ``` csharp foreach (var module in peImage.Imports) @@ -48,10 +48,10 @@ set of dependencies. AsmResolver provides a built-in implementation for calculating the Import Hash. The hash can be obtained by using the `GetImportHash` -extension method on `IPEImage`: +extension method on `PEImage`: ``` csharp -IPEImage image = ... +PEImage image = ... byte[] hash = image.GetImportHash(); ``` @@ -70,7 +70,7 @@ public class MySymbolResolver : ISymbolResolver } } -IPEImage image = ... +PEImage image = ... byte[] hash = image.GetImportHash(new MySymbolResolver()); ``` diff --git a/docs/guides/peimage/index.md b/docs/guides/peimage/index.md index c6a38963c..2fc399825 100644 --- a/docs/guides/peimage/index.md +++ b/docs/guides/peimage/index.md @@ -1,7 +1,7 @@ # Overview The PE image layer is the second layer of abstraction of the portable -executable (PE) file format. It is mostly represented by `IPEImage` and -its derivatives (such as `PEImage`), and works on top of the `PEFile` -layer. Its main purpose is to provide access to mutable models that are -easier to use than the raw data structures the PE file layer exposes. +executable (PE) file format. It is mostly represented by `PEImage`, and +works on top of the `PEFile` layer. Its main purpose is to provide access +to mutable models that are easier to use than the raw data structures the +PE file layer exposes. diff --git a/docs/guides/peimage/ready-to-run.md b/docs/guides/peimage/ready-to-run.md index 8c634ece7..958bc3373 100644 --- a/docs/guides/peimage/ready-to-run.md +++ b/docs/guides/peimage/ready-to-run.md @@ -15,7 +15,7 @@ To test whether a PE image has ReadyToRun metadata, query the ```csharp using AsmResolver.PE.DotNet.ReadyToRun; -IPEImage image = ... +PEImage image = ... var header = image.DotNetDirectory.ManagedNativeHeader; if (header is ReadyToRunDirectory directory) diff --git a/docs/guides/peimage/tls.md b/docs/guides/peimage/tls.md index 664a59b96..fb51dc0c9 100644 --- a/docs/guides/peimage/tls.md +++ b/docs/guides/peimage/tls.md @@ -75,7 +75,7 @@ base relocation directory of the PE image: ``` csharp using AsmResolver.PE.Relocations; -IPEImage image = ...; +PEImage image = ...; foreach (var relocation in tlsDirectory.GetRequiredBaseRelocations()) image.Relocations.Add(relocation); diff --git a/docs/guides/peimage/win32resources.md b/docs/guides/peimage/win32resources.md index 9151315ec..8f9387519 100644 --- a/docs/guides/peimage/win32resources.md +++ b/docs/guides/peimage/win32resources.md @@ -10,7 +10,7 @@ using AsmResolver.PE.Win32Resources; ## Directories -Resources are exposed by the `IPEImage.Resources` property, which +Resources are exposed by the `PEImage::Resources` property, which represents the root directory of all resources stored in the image. Every directory (including the root directory) is represented by instances of `IResourceDirectory`. This type contains the `Entries` @@ -19,7 +19,7 @@ containing more entries, or a data entry (an instance of `IResourceData`) with the raw contents of the resource. ``` csharp -IPEImage image = ... +PEImage image = ... IResourceDirectory root = image.Resources; foreach (var entry in root.Entries) @@ -35,7 +35,7 @@ Alternatively, you can access specific resources very easily by using the `GetDirectory` and `GetData`: ``` csharp -IPEImage image = ... +PEImage image = ... IResourceData stringDataEntry = image.Resources .GetDirectory(ResourceType.String) // Get string tables directory. .GetDirectory(251) // Get string block with ID 251 @@ -49,13 +49,13 @@ same ID is replaced with the new one, and that the sorting requirements according to the PE file specification are presrved. ``` csharp -IPEImage image = ... +PEImage image = ... var newDirectory = new ResourceDirectory(ResourceType.String); image.Resources.Entries.Add(newDirectory); ``` ``` csharp -IPEImage image = ... +PEImage image = ... var newDirectory = new ResourceDirectory(ResourceType.String); image.Resources.InsertOrReplaceEntry(newDirectory); ``` @@ -64,7 +64,7 @@ Similarly, removing can be done by modifying the `Entries` directory, or by using the `RemoveEntry` method: ``` csharp -IPEImage image = ... +PEImage image = ... image.Resources.RemoveEntry(ResourceType.String); ``` @@ -77,7 +77,7 @@ can check if this is a `IReadableSegment`, or use the shortcuts the entry. ``` csharp -IPEImage image = ... +PEImage image = ... IResourceData dataEntry = image.Resources .GetDirectory(ResourceType.String) // Get string tables directory. .GetDirectory(251) // Get string block with ID 251 @@ -94,7 +94,7 @@ Adding new data entries can be done by using the `ResourceData` constructor: ``` csharp -IPEImage image = ... +PEImage image = ... var data = new ResourceData(id: 1033, contents: new DataSegment(new byte[] { ... })); image.Resources