From 63e4fb433191e7c8b8ff61446c8dd69f76f3f058 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Fri, 11 Oct 2019 10:42:38 +0100 Subject: [PATCH 01/12] Various changes around integer types. --- Src/Workshell.PE/Content/CLR/CLRHeader.cs | 2 +- .../Content/CLR/CLRMetaDataHeader.cs | 4 +- .../Content/CLR/CLRMetaDataStreamTable.cs | 8 +- .../Content/LoadConfigurationCodeIntegrity.cs | 24 +- Src/Workshell.PE/DOSHeader.cs | 6 +- Src/Workshell.PE/DOSStub.cs | 4 +- Src/Workshell.PE/Extensions/Conversion.cs | 410 +++++------ Src/Workshell.PE/FileHeader.cs | 4 +- Src/Workshell.PE/Location.cs | 22 +- Src/Workshell.PE/LocationCalculator.cs | 73 +- Src/Workshell.PE/NTHeaders.cs | 6 +- Src/Workshell.PE/Native/IMAGE_DOS_HEADER.cs | 110 +-- Src/Workshell.PE/OptionalHeader.cs | 8 +- Src/Workshell.PE/SectionTable.cs | 8 +- .../Content/CLR/CLRMetaDataStreams.cs | 10 +- src/Workshell.PE/Content/Certificate.cs | 4 +- .../Content/Debug/DebugDirectory.cs | 6 +- .../Content/Exceptions/ExceptionTable64.cs | 2 +- .../Exceptions/ExceptionTableEntry64.cs | 2 +- .../Content/Exports/ExportDirectory.cs | 22 +- .../Content/Exports/ExportTable.cs | 6 +- src/Workshell.PE/Content/Exports/Exports.cs | 4 +- .../Imports/DelayedImportAddressTableEntry.cs | 70 +- .../Imports/DelayedImportAddressTables.cs | 10 +- .../Content/Imports/DelayedImportDirectory.cs | 16 +- .../Imports/DelayedImportHintNameEntry.cs | 70 +- .../Imports/DelayedImportHintNameTable.cs | 19 +- .../Content/Imports/DelayedImports.cs | 2 +- .../Content/Imports/ImportAddressTableBase.cs | 4 +- .../Imports/ImportAddressTableEntry.cs | 70 +- .../Imports/ImportAddressTableEntryBase.cs | 4 +- .../Content/Imports/ImportAddressTables.cs | 8 +- .../Imports/ImportAddressTablesBase.cs | 163 ++--- .../Content/Imports/ImportDirectory.cs | 16 +- .../Content/Imports/ImportDirectoryBase.cs | 164 ++--- .../Content/Imports/ImportHintNameEntry.cs | 70 +- .../Imports/ImportHintNameEntryBase.cs | 2 +- .../Content/Imports/ImportHintNameTable.cs | 19 +- .../Imports/ImportHintNameTableBase.cs | 183 ++--- src/Workshell.PE/Content/Imports/Imports.cs | 2 +- .../Content/LoadConfigurationDirectory.cs | 2 +- .../Content/Relocation/RelocationTable.cs | 2 +- .../Content/Resources/ResourceDataEntry.cs | 2 +- .../Content/Resources/ResourceDirectory.cs | 4 +- .../Resources/ResourceDirectoryEntry.cs | 2 +- src/Workshell.PE/Content/TLSDirectory.cs | 2 +- src/Workshell.PE/DataDirectories.cs | 6 +- src/Workshell.PE/Extensions/Stream.cs | 642 +++++++++--------- src/Workshell.PE/PortableExecutableImage.cs | 22 +- 49 files changed, 1194 insertions(+), 1127 deletions(-) diff --git a/Src/Workshell.PE/Content/CLR/CLRHeader.cs b/Src/Workshell.PE/Content/CLR/CLRHeader.cs index 960ed72..2413792 100644 --- a/Src/Workshell.PE/Content/CLR/CLRHeader.cs +++ b/Src/Workshell.PE/Content/CLR/CLRHeader.cs @@ -103,7 +103,7 @@ internal static async Task GetAsync(PortableExecutableImage image, Lo var location = new Location(image, clrLocation.FileOffset, clrLocation.RelativeVirtualAddress, clrLocation.VirtualAddress, size.ToUInt32(), size.ToUInt32(), clrLocation.Section); var stream = image.GetStream(); - stream.Seek(clrLocation.FileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(clrLocation.FileOffset, SeekOrigin.Begin); IMAGE_COR20_HEADER header; diff --git a/Src/Workshell.PE/Content/CLR/CLRMetaDataHeader.cs b/Src/Workshell.PE/Content/CLR/CLRMetaDataHeader.cs index 062f6ea..95bb7e9 100644 --- a/Src/Workshell.PE/Content/CLR/CLRMetaDataHeader.cs +++ b/Src/Workshell.PE/Content/CLR/CLRMetaDataHeader.cs @@ -55,12 +55,14 @@ public static async Task LoadAsync(PortableExecutableImage im var offset = mdLocation.FileOffset; var section = mdLocation.Section; - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); var signature = await stream.ReadUInt32Async().ConfigureAwait(false); if (signature != CLR_METADATA_SIGNATURE) + { throw new PortableExecutableImageException(image, "Incorrect signature found in CLR meta-data header."); + } var majorVersion = await stream.ReadUInt16Async().ConfigureAwait(false); var minorVersion = await stream.ReadUInt16Async().ConfigureAwait(false); diff --git a/Src/Workshell.PE/Content/CLR/CLRMetaDataStreamTable.cs b/Src/Workshell.PE/Content/CLR/CLRMetaDataStreamTable.cs index 321c41a..0d8245f 100644 --- a/Src/Workshell.PE/Content/CLR/CLRMetaDataStreamTable.cs +++ b/Src/Workshell.PE/Content/CLR/CLRMetaDataStreamTable.cs @@ -57,7 +57,7 @@ public static async Task LoadAsync(PortableExecutableIma var rva = calc.OffsetToRVA(offset); var va = imageBase + rva; var entries = await LoadTableAsync(image, header, offset, imageBase).ConfigureAwait(false); - ulong size = 0; + var size = 0L; foreach (var strm in entries) { @@ -75,11 +75,11 @@ public static async Task LoadAsync(PortableExecutableIma } } - private static async Task LoadTableAsync(PortableExecutableImage image, CLRMetaDataHeader header, ulong baseOffset, ulong imageBase) + private static async Task LoadTableAsync(PortableExecutableImage image, CLRMetaDataHeader header, long baseOffset, ulong imageBase) { var stream = image.GetStream(); - stream.Seek(baseOffset.ToInt64(),SeekOrigin.Begin); + stream.Seek(baseOffset,SeekOrigin.Begin); var entries = new List(); var offset = baseOffset; @@ -104,7 +104,9 @@ private static async Task LoadTableAsync(Portable size += 1; if (b <= 0) + { break; + } streamName.Append((char)b); } diff --git a/Src/Workshell.PE/Content/LoadConfigurationCodeIntegrity.cs b/Src/Workshell.PE/Content/LoadConfigurationCodeIntegrity.cs index bd9268a..19b13aa 100644 --- a/Src/Workshell.PE/Content/LoadConfigurationCodeIntegrity.cs +++ b/Src/Workshell.PE/Content/LoadConfigurationCodeIntegrity.cs @@ -1,4 +1,26 @@ -using System; +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/Src/Workshell.PE/DOSHeader.cs b/Src/Workshell.PE/DOSHeader.cs index a1701e5..133df2e 100644 --- a/Src/Workshell.PE/DOSHeader.cs +++ b/Src/Workshell.PE/DOSHeader.cs @@ -44,7 +44,7 @@ internal DOSHeader(PortableExecutableImage image, IMAGE_DOS_HEADER dosHeader, ul _image = image; _header = dosHeader; - Location = new Location(image, 0, 0, imageBase, Size.ToUInt32(), Size.ToUInt32()); + Location = new Location(image, 0, 0, imageBase, Size, Size); } #region Methods @@ -71,7 +71,7 @@ public async Task GetBytesAsync() #region Static Properties - public static int Size { get; } = Utils.SizeOf(); + public static uint Size { get; } = Utils.SizeOf().ToUInt32(); #endregion @@ -134,7 +134,7 @@ public async Task GetBytesAsync() public ushort[] Reserved2 => _header.e_res_2; [FieldAnnotation("File address of new header", Order = 19)] - public int FileAddressNewHeader => _header.e_lfanew; + public uint FileAddressNewHeader => _header.e_lfanew; #endregion } diff --git a/Src/Workshell.PE/DOSStub.cs b/Src/Workshell.PE/DOSStub.cs index 28ab3af..177fae9 100644 --- a/Src/Workshell.PE/DOSStub.cs +++ b/Src/Workshell.PE/DOSStub.cs @@ -33,11 +33,11 @@ public sealed class DOSStub : ISupportsLocation, ISupportsBytes { private readonly PortableExecutableImage _image; - internal DOSStub(PortableExecutableImage image, ulong stubOffset, uint stubSize, ulong imageBase) + internal DOSStub(PortableExecutableImage image, uint stubOffset, uint stubSize, ulong imageBase) { _image = image; - Location = new Location(image, stubOffset, Convert.ToUInt32(stubOffset), imageBase + stubOffset, stubSize, stubSize); + Location = new Location(image, stubOffset, stubOffset, imageBase + stubOffset, stubSize, stubSize); } #region Methods diff --git a/Src/Workshell.PE/Extensions/Conversion.cs b/Src/Workshell.PE/Extensions/Conversion.cs index 27c4028..88361d4 100644 --- a/Src/Workshell.PE/Extensions/Conversion.cs +++ b/Src/Workshell.PE/Extensions/Conversion.cs @@ -1,205 +1,205 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Workshell.PE.Extensions -{ - internal static class ConversionExtensions - { - #region int16 - - public static short ToInt16(this int value) - { - return Convert.ToInt16(value); - } - - public static short ToInt16(this long value) - { - return Convert.ToInt16(value); - } - - public static short ToInt16(this ushort value) - { - return Convert.ToInt16(value); - } - - public static short ToInt16(this uint value) - { - return Convert.ToInt16(value); - } - - public static short ToInt16(this ulong value) - { - return Convert.ToInt16(value); - } - - #endregion - - #region int32 - - public static int ToInt32(this short value) - { - return value; - } - - public static int ToInt32(this long value) - { - return Convert.ToInt32(value); - } - - public static int ToInt32(this ushort value) - { - return Convert.ToInt32(value); - } - - public static int ToInt32(this uint value) - { - return Convert.ToInt32(value); - } - - public static int ToInt32(this ulong value) - { - return Convert.ToInt32(value); - } - - #endregion - - #region int64 - - public static long ToInt64(this short value) - { - return value; - } - - public static long ToInt64(this int value) - { - return value; - } - - public static long ToInt64(this ushort value) - { - return Convert.ToInt64(value); - } - - public static long ToInt64(this uint value) - { - return Convert.ToInt64(value); - } - - public static long ToInt64(this ulong value) - { - return Convert.ToInt32(value); - } - - #endregion - - #region uint16 - - public static ushort ToUInt16(this short value) - { - return Convert.ToUInt16(value); - } - - public static ushort ToUInt16(this int value) - { - return Convert.ToUInt16(value); - } - - public static ushort ToUInt16(this long value) - { - return Convert.ToUInt16(value); - } - - public static ushort ToUInt16(this uint value) - { - return Convert.ToUInt16(value); - } - - public static ushort ToUInt16(this ulong value) - { - return Convert.ToUInt16(value); - } - - #endregion - - #region uint32 - - public static uint ToUInt32(this short value) - { - return Convert.ToUInt32(value); - } - - public static uint ToUInt32(this int value) - { - return Convert.ToUInt32(value); - } - - public static uint ToUInt32(this long value) - { - return Convert.ToUInt32(value); - } - - public static uint ToUInt32(this ushort value) - { - return value; - } - - public static uint ToUInt32(this ulong value) - { - return Convert.ToUInt32(value); - } - - #endregion - - #region uint64 - - public static ulong ToUInt64(this short value) - { - return Convert.ToUInt64(value); - } - - public static ulong ToUInt64(this int value) - { - return Convert.ToUInt64(value); - } - - public static ulong ToUInt64(this long value) - { - return Convert.ToUInt64(value); - } - - public static ulong ToUInt64(this ushort value) - { - return value; - } - - public static ulong ToUInt64(this uint value) - { - return value; - } - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Workshell.PE.Extensions +{ + internal static class ConversionExtensions + { + #region Int16 + + public static short ToInt16(this int value) + { + return Convert.ToInt16(value); + } + + public static short ToInt16(this long value) + { + return Convert.ToInt16(value); + } + + public static short ToInt16(this ushort value) + { + return Convert.ToInt16(value); + } + + public static short ToInt16(this uint value) + { + return Convert.ToInt16(value); + } + + public static short ToInt16(this ulong value) + { + return Convert.ToInt16(value); + } + + #endregion + + #region Int32 + + public static int ToInt32(this short value) + { + return value; + } + + public static int ToInt32(this long value) + { + return Convert.ToInt32(value); + } + + public static int ToInt32(this ushort value) + { + return Convert.ToInt32(value); + } + + public static int ToInt32(this uint value) + { + return Convert.ToInt32(value); + } + + public static int ToInt32(this ulong value) + { + return Convert.ToInt32(value); + } + + #endregion + + #region Int64 + + public static long ToInt64(this short value) + { + return value; + } + + public static long ToInt64(this int value) + { + return value; + } + + public static long ToInt64(this ushort value) + { + return Convert.ToInt64(value); + } + + public static long ToInt64(this uint value) + { + return Convert.ToInt64(value); + } + + public static long ToInt64(this ulong value) + { + return Convert.ToInt32(value); + } + + #endregion + + #region UInt16 + + public static ushort ToUInt16(this short value) + { + return Convert.ToUInt16(value); + } + + public static ushort ToUInt16(this int value) + { + return Convert.ToUInt16(value); + } + + public static ushort ToUInt16(this long value) + { + return Convert.ToUInt16(value); + } + + public static ushort ToUInt16(this uint value) + { + return Convert.ToUInt16(value); + } + + public static ushort ToUInt16(this ulong value) + { + return Convert.ToUInt16(value); + } + + #endregion + + #region UInt32 + + public static uint ToUInt32(this short value) + { + return Convert.ToUInt32(value); + } + + public static uint ToUInt32(this int value) + { + return Convert.ToUInt32(value); + } + + public static uint ToUInt32(this long value) + { + return Convert.ToUInt32(value); + } + + public static uint ToUInt32(this ushort value) + { + return value; + } + + public static uint ToUInt32(this ulong value) + { + return Convert.ToUInt32(value); + } + + #endregion + + #region UInt64 + + public static ulong ToUInt64(this short value) + { + return Convert.ToUInt64(value); + } + + public static ulong ToUInt64(this int value) + { + return Convert.ToUInt64(value); + } + + public static ulong ToUInt64(this long value) + { + return Convert.ToUInt64(value); + } + + public static ulong ToUInt64(this ushort value) + { + return value; + } + + public static ulong ToUInt64(this uint value) + { + return value; + } + + #endregion + } +} diff --git a/Src/Workshell.PE/FileHeader.cs b/Src/Workshell.PE/FileHeader.cs index 8387332..db801dd 100644 --- a/Src/Workshell.PE/FileHeader.cs +++ b/Src/Workshell.PE/FileHeader.cs @@ -91,12 +91,12 @@ public sealed class FileHeader : ISupportsLocation, ISupportsBytes private readonly PortableExecutableImage _image; private readonly IMAGE_FILE_HEADER _header; - internal FileHeader(PortableExecutableImage image, IMAGE_FILE_HEADER fileHeader, ulong headerOffset, ulong imageBase) + internal FileHeader(PortableExecutableImage image, IMAGE_FILE_HEADER fileHeader, uint headerOffset, ulong imageBase) { _image = image; _header = fileHeader; - Location = new Location(image, headerOffset, headerOffset.ToUInt32(), imageBase + headerOffset, Size.ToUInt32(), Size.ToUInt32()); + Location = new Location(image, headerOffset, headerOffset, imageBase + headerOffset, Size.ToUInt32(), Size.ToUInt32()); } #region Methods diff --git a/Src/Workshell.PE/Location.cs b/Src/Workshell.PE/Location.cs index 1ba4660..c733f53 100644 --- a/Src/Workshell.PE/Location.cs +++ b/Src/Workshell.PE/Location.cs @@ -31,24 +31,12 @@ public sealed class Location : IEquatable private readonly PortableExecutableImage _image; private Section _section; - internal Location(PortableExecutableImage image, ulong fileOffset, uint rva, ulong va, ulong fileSize, ulong virtualSize) + internal Location(PortableExecutableImage image, long fileOffset, uint rva, ulong va, long fileSize, long virtualSize) : this(image, fileOffset, rva, va, fileSize, virtualSize, null) { } - /* - public Location(ulong fileOffset, uint rva, ulong va, ulong fileSize, ulong virtualSize) - : this(null, fileOffset, rva, va, fileSize, virtualSize, ?) - { - } - - public Location(ulong fileOffset, uint rva, ulong va, ulong fileSize, ulong virtualSize, Section section) - : this(null, fileOffset, rva, va, fileSize, virtualSize, section) - { - } - */ - - internal Location(PortableExecutableImage image, ulong fileOffset, uint rva, ulong va, ulong fileSize, ulong virtualSize, Section section) + internal Location(PortableExecutableImage image, long fileOffset, uint rva, ulong va, long fileSize, long virtualSize, Section section) { _image = image; _section = section; @@ -132,11 +120,11 @@ public override int GetHashCode() #region Properties - public ulong FileOffset { get; } - public ulong FileSize { get; } + public long FileOffset { get; } + public long FileSize { get; } public uint RelativeVirtualAddress { get; } public ulong VirtualAddress { get; } - public ulong VirtualSize { get; } + public long VirtualSize { get; } public Section Section { diff --git a/Src/Workshell.PE/LocationCalculator.cs b/Src/Workshell.PE/LocationCalculator.cs index face89b..11b2494 100644 --- a/Src/Workshell.PE/LocationCalculator.cs +++ b/Src/Workshell.PE/LocationCalculator.cs @@ -25,6 +25,8 @@ using System.Linq; using System.Text; +using Workshell.PE.Extensions; + namespace Workshell.PE { public sealed class LocationCalculator @@ -38,7 +40,7 @@ internal LocationCalculator(PortableExecutableImage image) #region Methods - public Location OffsetToLocation(ulong offset, ulong size) + public Location OffsetToLocation(long offset, long size) { var rva = OffsetToRVA(offset); var va = OffsetToVA(offset); @@ -51,7 +53,7 @@ public Location OffsetToLocation(ulong offset, ulong size) public Section VAToSection(ulong va) { var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; - var rva = Convert.ToUInt32(va - imageBase); + var rva = (va - imageBase).ToUInt32(); return RVAToSection(rva); } @@ -59,58 +61,63 @@ public Section VAToSection(ulong va) public SectionTableEntry VAToSectionTableEntry(ulong va) { var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; - var rva = Convert.ToUInt32(va - imageBase); + var rva = (va - imageBase).ToUInt32(); return RVAToSectionTableEntry(rva); } - public ulong VAToOffset(ulong va) + public long VAToOffset(ulong va) { var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; - var rva = Convert.ToUInt32(va - imageBase); + var rva = (va - imageBase).ToUInt32(); return RVAToOffset(rva); } - public ulong VAToOffset(Section section, ulong va) + public long VAToOffset(Section section, ulong va) { - return VAToOffset(section.TableEntry,va); + return VAToOffset(section.TableEntry, va); } - public ulong VAToOffset(SectionTableEntry section, ulong va) + public long VAToOffset(SectionTableEntry section, ulong va) { var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; - var rva = Convert.ToUInt32(va - imageBase); + var rva = (va - imageBase).ToUInt32(); - return RVAToOffset(section,rva); + return RVAToOffset(section, rva); } - public ulong OffsetToVA(ulong offset) + public ulong OffsetToVA(long offset) { - var entries = _image.SectionTable.OrderBy(e => e.PointerToRawData).ToArray(); + var entries = _image.SectionTable.OrderBy(e => e.PointerToRawData) + .ToArray(); SectionTableEntry entry = null; for(var i = 0; i < entries.Length; i++) { if (offset >= entries[i].PointerToRawData && offset < (entries[i].PointerToRawData + entries[i].SizeOfRawData)) + { entry = entries[i]; + } } if (entry != null) + { return OffsetToVA(entry, offset); - + } + return 0; } - public ulong OffsetToVA(Section section, ulong offset) + public ulong OffsetToVA(Section section, long offset) { - return OffsetToVA(section.TableEntry,offset); + return OffsetToVA(section.TableEntry, offset); } - public ulong OffsetToVA(SectionTableEntry section, ulong offset) + public ulong OffsetToVA(SectionTableEntry section, long offset) { var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; - var rva = Convert.ToUInt32((offset + section.VirtualAddress) - section.PointerToRawData); + var rva = ((offset + section.VirtualAddress) - section.PointerToRawData).ToUInt32(); return imageBase + rva; } @@ -157,60 +164,70 @@ public SectionTableEntry RVAToSectionTableEntry(uint rva) return entry; } - public ulong RVAToOffset(uint rva) + public long RVAToOffset(uint rva) { - var entries = _image.SectionTable.OrderBy(e => e.VirtualAddress).ToArray(); + var entries = _image.SectionTable.OrderBy(e => e.VirtualAddress) + .ToArray(); SectionTableEntry entry = null; for (var i = 0; i < entries.Length; i++) { if (rva >= entries[i].VirtualAddress && rva < (entries[i].VirtualAddress + entries[i].SizeOfRawData)) + { entry = entries[i]; + } } if (entry != null) + { return RVAToOffset(entry, rva); + } return 0; } - public ulong RVAToOffset(Section section, uint rva) + public long RVAToOffset(Section section, uint rva) { - return RVAToOffset(section.TableEntry,rva); + return RVAToOffset(section.TableEntry, rva); } - public ulong RVAToOffset(SectionTableEntry section, uint rva) + public long RVAToOffset(SectionTableEntry section, uint rva) { var offset = (rva - section.VirtualAddress) + section.PointerToRawData; return offset; } - public uint OffsetToRVA(ulong offset) + public uint OffsetToRVA(long offset) { - var entries = _image.SectionTable.OrderBy(e => e.PointerToRawData).ToArray(); + var entries = _image.SectionTable.OrderBy(e => e.PointerToRawData) + .ToArray(); SectionTableEntry entry = null; for (var i = 0; i < entries.Length; i++) { if (offset >= entries[i].PointerToRawData && offset < (entries[i].PointerToRawData + entries[i].SizeOfRawData)) + { entry = entries[i]; + } } if (entry != null) + { return OffsetToRVA(entry, offset); + } return 0; } - public uint OffsetToRVA(Section section, ulong offset) + public uint OffsetToRVA(Section section, long offset) { - return OffsetToRVA(section.TableEntry,offset); + return OffsetToRVA(section.TableEntry, offset); } - public uint OffsetToRVA(SectionTableEntry section, ulong offset) + public uint OffsetToRVA(SectionTableEntry section, long offset) { - var rva = Convert.ToUInt32((offset + section.VirtualAddress) - section.PointerToRawData); + var rva = ((offset + section.VirtualAddress) - section.PointerToRawData).ToUInt32(); return rva; } diff --git a/Src/Workshell.PE/NTHeaders.cs b/Src/Workshell.PE/NTHeaders.cs index 4482bbd..da6f0ff 100644 --- a/Src/Workshell.PE/NTHeaders.cs +++ b/Src/Workshell.PE/NTHeaders.cs @@ -34,13 +34,13 @@ public sealed class NTHeaders : ISupportsLocation, ISupportsBytes private readonly PortableExecutableImage _image; - internal NTHeaders(PortableExecutableImage image, ulong headerOffset, ulong imageBase, FileHeader fileHeader, OptionalHeader optHeader, DataDirectories dataDirs) + internal NTHeaders(PortableExecutableImage image, uint headerOffset, ulong imageBase, FileHeader fileHeader, OptionalHeader optHeader, DataDirectories dataDirs) { _image = image; - var size = (4U + fileHeader.Location.FileSize + optHeader.Location.FileSize + dataDirs.Location.FileSize).ToUInt32(); + var size = (4 + fileHeader.Location.FileSize + optHeader.Location.FileSize + dataDirs.Location.FileSize).ToUInt32(); - Location = new Location(image, headerOffset, headerOffset.ToUInt32(), imageBase + headerOffset, size, size); + Location = new Location(image, headerOffset, headerOffset, imageBase + headerOffset, size, size); FileHeader = fileHeader; OptionalHeader = optHeader; DataDirectories = dataDirs; diff --git a/Src/Workshell.PE/Native/IMAGE_DOS_HEADER.cs b/Src/Workshell.PE/Native/IMAGE_DOS_HEADER.cs index 34180fd..e0088f6 100644 --- a/Src/Workshell.PE/Native/IMAGE_DOS_HEADER.cs +++ b/Src/Workshell.PE/Native/IMAGE_DOS_HEADER.cs @@ -1,55 +1,55 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Text; - -namespace Workshell.PE.Native -{ - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct IMAGE_DOS_HEADER - { - public ushort e_magic; // Magic number - public ushort e_cblp; // Bytes on last page of file - public ushort e_cp; // Pages in file - public ushort e_crlc; // Relocations - public ushort e_cparhdr; // Size of header in paragraphs - public ushort e_minalloc; // Minimum extra paragraphs needed - public ushort e_maxalloc; // Maximum extra paragraphs needed - public ushort e_ss; // Initial (relative) SS value - public ushort e_sp; // Initial SP value - public ushort e_csum; // Checksum - public ushort e_ip; // Initial IP value - public ushort e_cs; // Initial (relative) CS value - public ushort e_lfarlc; // File address of relocation table - public ushort e_ovno; // Overlay number - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public ushort[] e_res_1; // Reserved words - public ushort e_oemid; // OEM identifier (for e_oeminfo) - public ushort e_oeminfo; // OEM information; e_oemid specific - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public ushort[] e_res_2; // Reserved words - public int e_lfanew; // File address of new exe header - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace Workshell.PE.Native +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct IMAGE_DOS_HEADER + { + public ushort e_magic; // Magic number + public ushort e_cblp; // Bytes on last page of file + public ushort e_cp; // Pages in file + public ushort e_crlc; // Relocations + public ushort e_cparhdr; // Size of header in paragraphs + public ushort e_minalloc; // Minimum extra paragraphs needed + public ushort e_maxalloc; // Maximum extra paragraphs needed + public ushort e_ss; // Initial (relative) SS value + public ushort e_sp; // Initial SP value + public ushort e_csum; // Checksum + public ushort e_ip; // Initial IP value + public ushort e_cs; // Initial (relative) CS value + public ushort e_lfarlc; // File address of relocation table + public ushort e_ovno; // Overlay number + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public ushort[] e_res_1; // Reserved words + public ushort e_oemid; // OEM identifier (for e_oeminfo) + public ushort e_oeminfo; // OEM information; e_oemid specific + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public ushort[] e_res_2; // Reserved words + public uint e_lfanew; // File address of new exe header + } +} diff --git a/Src/Workshell.PE/OptionalHeader.cs b/Src/Workshell.PE/OptionalHeader.cs index 726271b..af051ae 100644 --- a/Src/Workshell.PE/OptionalHeader.cs +++ b/Src/Workshell.PE/OptionalHeader.cs @@ -103,13 +103,13 @@ public abstract class OptionalHeader : ISupportsLocation, ISupportsBytes { private readonly PortableExecutableImage _image; - internal OptionalHeader(PortableExecutableImage image, ulong headerOffset, uint headerSize, ulong imageBase, ushort magic) + internal OptionalHeader(PortableExecutableImage image, uint headerOffset, uint headerSize, ulong imageBase, ushort magic) { _image = image; var headerSizeWithMagic = sizeof(ushort) + headerSize; - Location = new Location(image, headerOffset, headerOffset.ToUInt32(), imageBase + headerOffset, headerSizeWithMagic, headerSizeWithMagic); + Location = new Location(image, headerOffset, headerOffset, imageBase + headerOffset, headerSizeWithMagic, headerSizeWithMagic); Magic = magic; } @@ -273,7 +273,7 @@ public sealed class OptionalHeader32 : OptionalHeader { private readonly IMAGE_OPTIONAL_HEADER32 _header; - internal OptionalHeader32(PortableExecutableImage image, IMAGE_OPTIONAL_HEADER32 optHeader, ulong headerOffset, ulong imageBase, ushort magic) : base(image, headerOffset, OptionalHeader.Size32.ToUInt32(), imageBase, magic) + internal OptionalHeader32(PortableExecutableImage image, IMAGE_OPTIONAL_HEADER32 optHeader, uint headerOffset, ulong imageBase, ushort magic) : base(image, headerOffset, OptionalHeader.Size32.ToUInt32(), imageBase, magic) { _header = optHeader; } @@ -317,7 +317,7 @@ public sealed class OptionalHeader64 : OptionalHeader { private readonly IMAGE_OPTIONAL_HEADER64 _header; - internal OptionalHeader64(PortableExecutableImage image, IMAGE_OPTIONAL_HEADER64 optHeader, ulong headerOffset, ulong imageBase, ushort magic) : base(image, headerOffset, OptionalHeader.Size64.ToUInt32(), imageBase, magic) + internal OptionalHeader64(PortableExecutableImage image, IMAGE_OPTIONAL_HEADER64 optHeader, uint headerOffset, ulong imageBase, ushort magic) : base(image, headerOffset, OptionalHeader.Size64.ToUInt32(), imageBase, magic) { _header = optHeader; } diff --git a/Src/Workshell.PE/SectionTable.cs b/Src/Workshell.PE/SectionTable.cs index 846e1ac..c770d9f 100644 --- a/Src/Workshell.PE/SectionTable.cs +++ b/Src/Workshell.PE/SectionTable.cs @@ -129,13 +129,13 @@ public sealed class SectionTableEntry : IEquatable, ISupports private readonly PortableExecutableImage _image; private readonly IMAGE_SECTION_HEADER _header; - internal SectionTableEntry(PortableExecutableImage image, SectionTable sectionTable, IMAGE_SECTION_HEADER entryHeader, ulong entryOffset, ulong imageBase) + internal SectionTableEntry(PortableExecutableImage image, SectionTable sectionTable, IMAGE_SECTION_HEADER entryHeader, uint entryOffset, ulong imageBase) { _image = image; _header = entryHeader; Table = sectionTable; - Location = new Location(image, entryOffset, entryOffset.ToUInt32(), imageBase + entryOffset, _headerSize, _headerSize); + Location = new Location(image, entryOffset, entryOffset, imageBase + entryOffset, _headerSize, _headerSize); Name = GetName(); } @@ -275,14 +275,14 @@ public sealed class SectionTable : IEnumerable, ISupportsLoca private readonly PortableExecutableImage _image; private readonly SectionTableEntry[] _table; - internal SectionTable(PortableExecutableImage image, IMAGE_SECTION_HEADER[] sectionHeaders, ulong tableOffset, ulong imageBase) + internal SectionTable(PortableExecutableImage image, IMAGE_SECTION_HEADER[] sectionHeaders, uint tableOffset, ulong imageBase) { _image = image; _table = new SectionTableEntry[sectionHeaders.Length]; var size = (Utils.SizeOf() * sectionHeaders.Length).ToUInt32(); - Location = new Location(image, tableOffset, tableOffset.ToUInt32(), imageBase + tableOffset, size, size); + Location = new Location(image, tableOffset, tableOffset, imageBase + tableOffset, size, size); var offset = tableOffset; diff --git a/src/Workshell.PE/Content/CLR/CLRMetaDataStreams.cs b/src/Workshell.PE/Content/CLR/CLRMetaDataStreams.cs index ecac3cb..ecf2926 100644 --- a/src/Workshell.PE/Content/CLR/CLRMetaDataStreams.cs +++ b/src/Workshell.PE/Content/CLR/CLRMetaDataStreams.cs @@ -61,10 +61,10 @@ internal static Task LoadAsync(PortableExecutableImage image streams[i] = stream; } - uint rva = 0; - ulong va = 0; - ulong offset = 0; - ulong size = 0; + var rva = 0U; + var va = 0UL; + var offset = 0L; + var size = 0L; if (streams.Length > 0) { @@ -76,7 +76,9 @@ internal static Task LoadAsync(PortableExecutableImage image } foreach (var stream in streams) + { size += stream.Location.FileSize; + } var location = new Location(image, offset, rva, va, size, size); var result = new CLRMetaDataStreams(image, location, streams); diff --git a/src/Workshell.PE/Content/Certificate.cs b/src/Workshell.PE/Content/Certificate.cs index 20bed25..88d5d41 100644 --- a/src/Workshell.PE/Content/Certificate.cs +++ b/src/Workshell.PE/Content/Certificate.cs @@ -107,13 +107,15 @@ public async Task GetCertificateDataAsync() var offset = Location.FileOffset + Utils.SizeOf().ToUInt32(); var stream = Image.GetStream(); - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); var buffer = new byte[Length]; var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (numRead == 0) + { throw new PortableExecutableImageException(Image, "Could not read certificate data from stream."); + } return buffer; } diff --git a/src/Workshell.PE/Content/Debug/DebugDirectory.cs b/src/Workshell.PE/Content/Debug/DebugDirectory.cs index fc1cb8d..9a69a40 100644 --- a/src/Workshell.PE/Content/Debug/DebugDirectory.cs +++ b/src/Workshell.PE/Content/Debug/DebugDirectory.cs @@ -78,13 +78,13 @@ public static async Task GetAsync(PortableExecutableImage image) var entrySize = Utils.SizeOf(); var entryCount = dataDirectory.Size / entrySize; - var entries = new Tuple[entryCount]; + var entries = new Tuple[entryCount]; for (var i = 0; i < entryCount; i++) { var entry = await stream.ReadStructAsync(entrySize).ConfigureAwait(false); - entries[i] = new Tuple(fileOffset, entry); + entries[i] = new Tuple(fileOffset, entry); } var directoryEntries = LoadEntries(image, entrySize, entries); @@ -98,7 +98,7 @@ public static async Task GetAsync(PortableExecutableImage image) } } - private static DebugDirectoryEntry[] LoadEntries(PortableExecutableImage image, int entrySize, Tuple[] entries) + private static DebugDirectoryEntry[] LoadEntries(PortableExecutableImage image, int entrySize, Tuple[] entries) { var calc = image.GetCalculator(); var imageBase = image.NTHeaders.OptionalHeader.ImageBase; diff --git a/src/Workshell.PE/Content/Exceptions/ExceptionTable64.cs b/src/Workshell.PE/Content/Exceptions/ExceptionTable64.cs index 1a570a9..6abbef0 100644 --- a/src/Workshell.PE/Content/Exceptions/ExceptionTable64.cs +++ b/src/Workshell.PE/Content/Exceptions/ExceptionTable64.cs @@ -46,7 +46,7 @@ internal static async Task GetAsync(PortableExecutableImage imag var offset = calc.RVAToOffset(dataDirectory.VirtualAddress); var rva = dataDirectory.VirtualAddress; - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); var entrySize = Utils.SizeOf(); var entries = new List(); diff --git a/src/Workshell.PE/Content/Exceptions/ExceptionTableEntry64.cs b/src/Workshell.PE/Content/Exceptions/ExceptionTableEntry64.cs index c4a6647..b62b7f1 100644 --- a/src/Workshell.PE/Content/Exceptions/ExceptionTableEntry64.cs +++ b/src/Workshell.PE/Content/Exceptions/ExceptionTableEntry64.cs @@ -69,7 +69,7 @@ public async Task GetUnwindInfoAsync() { var offset = calc.RVAToOffset(UnwindInfoAddress); - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); var versionFlags = await stream.ReadByteAsync().ConfigureAwait(false); var sizeOfProlog = await stream.ReadByteAsync().ConfigureAwait(false); diff --git a/src/Workshell.PE/Content/Exports/ExportDirectory.cs b/src/Workshell.PE/Content/Exports/ExportDirectory.cs index 9b22654..8c7d01b 100644 --- a/src/Workshell.PE/Content/Exports/ExportDirectory.cs +++ b/src/Workshell.PE/Content/Exports/ExportDirectory.cs @@ -93,7 +93,7 @@ public static async Task GetAsync(PortableExecutableImage image var location = new Location(image, offset, rva, va, size.ToUInt32(), size.ToUInt32(), section); var stream = image.GetStream(); - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); var exportDirectory = await stream.ReadStructAsync(size).ConfigureAwait(false); var name = await BuildNameAsync(calc, stream, exportDirectory).ConfigureAwait(false); @@ -112,16 +112,18 @@ public static async Task GetAsync(PortableExecutableImage image private static async Task BuildNameAsync(LocationCalculator calc, Stream stream, IMAGE_EXPORT_DIRECTORY directory) { var builder = new StringBuilder(256); - var offset = calc.RVAToOffset(directory.Name).ToInt64(); + var offset = calc.RVAToOffset(directory.Name); stream.Seek(offset, SeekOrigin.Begin); while (true) { - int value = await stream.ReadByteAsync().ConfigureAwait(false); + var value = await stream.ReadByteAsync().ConfigureAwait(false); - if (value <= 0) + if (value == 0) + { break; + } var c = (char)value; @@ -133,42 +135,48 @@ private static async Task BuildNameAsync(LocationCalculator calc, Stream private static async Task BuildFunctionAddressesAsync(LocationCalculator calc, Stream stream, IMAGE_EXPORT_DIRECTORY directory) { - var offset = calc.RVAToOffset(directory.AddressOfFunctions).ToInt64(); + var offset = calc.RVAToOffset(directory.AddressOfFunctions); stream.Seek(offset, SeekOrigin.Begin); var results = new uint[directory.NumberOfFunctions]; for (var i = 0; i < directory.NumberOfFunctions; i++) + { results[i] = await stream.ReadUInt32Async().ConfigureAwait(false); + } return results; } private static async Task BuildFunctionNameAddressesAsync(LocationCalculator calc, Stream stream, IMAGE_EXPORT_DIRECTORY directory) { - var offset = calc.RVAToOffset(directory.AddressOfNames).ToInt64(); + var offset = calc.RVAToOffset(directory.AddressOfNames); stream.Seek(offset, SeekOrigin.Begin); var results = new uint[directory.NumberOfNames]; for (var i = 0; i < directory.NumberOfNames; i++) + { results[i] = await stream.ReadUInt32Async().ConfigureAwait(false); + } return results; } private static async Task BuildFunctionOrdinalsAsync(LocationCalculator calc, Stream stream, IMAGE_EXPORT_DIRECTORY directory) { - var offset = calc.RVAToOffset(directory.AddressOfNameOrdinals).ToInt64(); + var offset = calc.RVAToOffset(directory.AddressOfNameOrdinals); stream.Seek(offset, SeekOrigin.Begin); var results = new ushort[directory.NumberOfNames]; for (var i = 0; i < directory.NumberOfNames; i++) + { results[i] = await stream.ReadUInt16Async().ConfigureAwait(false); + } return results; } diff --git a/src/Workshell.PE/Content/Exports/ExportTable.cs b/src/Workshell.PE/Content/Exports/ExportTable.cs index 7d25e55..89486a4 100644 --- a/src/Workshell.PE/Content/Exports/ExportTable.cs +++ b/src/Workshell.PE/Content/Exports/ExportTable.cs @@ -51,7 +51,7 @@ public static async Task> GetFunctionAddressTableAsync(Portabl var location = new Location(image, fileOffset, directory.AddressOfFunctions, imageBase + directory.AddressOfFunctions, size, size, section); var stream = image.GetStream(); - stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(fileOffset, SeekOrigin.Begin); var addresses = new uint[directory.NumberOfFunctions]; @@ -85,7 +85,7 @@ public static async Task> GetNameAddressTableAsync(PortableExe var location = new Location(image, fileOffset, directory.AddressOfNames, imageBase + directory.AddressOfNames, size, size, section); var stream = image.GetStream(); - stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(fileOffset, SeekOrigin.Begin); var addresses = new uint[directory.NumberOfNames]; @@ -119,7 +119,7 @@ public static async Task> GetOrdinalTableAsync(PortableExecu var location = new Location(image, fileOffset, directory.AddressOfNameOrdinals, imageBase + directory.AddressOfNameOrdinals, size, size, section); var stream = image.GetStream(); - stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(fileOffset, SeekOrigin.Begin); var ordinals = new ushort[directory.NumberOfNames]; diff --git a/src/Workshell.PE/Content/Exports/Exports.cs b/src/Workshell.PE/Content/Exports/Exports.cs index ce167eb..408f1c4 100644 --- a/src/Workshell.PE/Content/Exports/Exports.cs +++ b/src/Workshell.PE/Content/Exports/Exports.cs @@ -130,7 +130,7 @@ public static async Task GetAsync(PortableExecutableImage image, Export if (address >= dataDirectory.VirtualAddress && address <= (dataDirectory.VirtualAddress + dataDirectory.Size)) { - var offset = calc.RVAToOffset(address).ToInt64(); + var offset = calc.RVAToOffset(address); info.ForwardName = await GetStringAsync(stream, offset).ConfigureAwait(false); } @@ -144,7 +144,7 @@ public static async Task GetAsync(PortableExecutableImage image, Export { var nameAddress = nameAddresses[i]; var ordinal = ordinals[i]; - var offset = calc.RVAToOffset(nameAddress).ToInt64(); + var offset = calc.RVAToOffset(nameAddress); var info = infos[ordinal]; info.NameAddress = nameAddress; diff --git a/src/Workshell.PE/Content/Imports/DelayedImportAddressTableEntry.cs b/src/Workshell.PE/Content/Imports/DelayedImportAddressTableEntry.cs index 7184607..4bc15b5 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportAddressTableEntry.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportAddressTableEntry.cs @@ -1,35 +1,35 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Workshell.PE.Content -{ - public sealed class DelayedImportAddressTableEntry : ImportAddressTableEntryBase - { - internal DelayedImportAddressTableEntry(PortableExecutableImage image, ulong entryOffset, ulong entryValue, uint entryAddress, ushort entryOrdinal, bool isOrdinal) : base(image, entryOffset, entryValue, entryAddress, entryOrdinal, isOrdinal, true) - { - } - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Workshell.PE.Content +{ + public sealed class DelayedImportAddressTableEntry : ImportAddressTableEntryBase + { + internal DelayedImportAddressTableEntry(PortableExecutableImage image, long entryOffset, ulong entryValue, uint entryAddress, ushort entryOrdinal, bool isOrdinal) : base(image, entryOffset, entryValue, entryAddress, entryOrdinal, isOrdinal, true) + { + } + } +} diff --git a/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs b/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs index 22a2d07..93a32cb 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs @@ -32,7 +32,7 @@ namespace Workshell.PE.Content { public sealed class DelayedImportAddressTables: ImportAddressTablesBase { - internal DelayedImportAddressTables(PortableExecutableImage image, DataDirectory dataDirectory, Location location, Tuple[] tables) : base(image, dataDirectory, location, tables, false) + internal DelayedImportAddressTables(PortableExecutableImage image, DataDirectory dataDirectory, Location location, IEnumerable> tables) : base(image, dataDirectory, location, tables, false) { } @@ -67,7 +67,7 @@ private static async Task GetTableAsync(PortableExec var entries = new List(); var offset = calc.RVAToOffset(thunk); - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); while (true) { @@ -92,18 +92,18 @@ private static async Task GetTableAsync(PortableExec var imageBase = image.NTHeaders.OptionalHeader.ImageBase; var va = imageBase + rva; var fileOffset = calc.RVAToOffset(rva); - var fileSize = 0ul; + var fileSize = 0L; foreach (var table in tables) { var size = (table.Item2.Length + 1) * (!image.Is64Bit ? sizeof(uint) : sizeof(ulong)); - fileSize += size.ToUInt32(); + fileSize += size; } var section = calc.RVAToSection(rva); var location = new Location(image, fileOffset, rva, va, fileSize, fileSize, section); - var result = new DelayedImportAddressTables(image, directory.DataDirectory, location, tables.ToArray()); + var result = new DelayedImportAddressTables(image, directory.DataDirectory, location, tables); return result; } diff --git a/src/Workshell.PE/Content/Imports/DelayedImportDirectory.cs b/src/Workshell.PE/Content/Imports/DelayedImportDirectory.cs index 6119203..3d919c9 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportDirectory.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportDirectory.cs @@ -48,37 +48,43 @@ public static DelayedImportDirectory Get(PortableExecutableImage image) public static async Task GetAsync(PortableExecutableImage image) { if (!image.NTHeaders.DataDirectories.Exists(DataDirectoryType.DelayImportDescriptor)) + { return null; + } var dataDirectory = image.NTHeaders.DataDirectories[DataDirectoryType.DelayImportDescriptor]; if (DataDirectory.IsNullOrEmpty(dataDirectory)) + { return null; + } var calc = image.GetCalculator(); var section = calc.RVAToSection(dataDirectory.VirtualAddress); var fileOffset = calc.RVAToOffset(section, dataDirectory.VirtualAddress); var stream = image.GetStream(); - stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(fileOffset, SeekOrigin.Begin); var size = Utils.SizeOf(); - var descriptors = new List>(); + var descriptors = new List>(); try { - ulong offset = 0; + var offset = 0L; while (true) { var descriptor = await stream.ReadStructAsync(size).ConfigureAwait(false); if (descriptor.Name == 0 && descriptor.ModuleHandle == 0) + { break; + } - var tuple = new Tuple(offset, descriptor); + var tuple = new Tuple(offset, descriptor); - offset += size.ToUInt32(); + offset += size; descriptors.Add(tuple); } diff --git a/src/Workshell.PE/Content/Imports/DelayedImportHintNameEntry.cs b/src/Workshell.PE/Content/Imports/DelayedImportHintNameEntry.cs index 1c3593c..ab7def0 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportHintNameEntry.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportHintNameEntry.cs @@ -1,35 +1,35 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Workshell.PE.Content -{ - public sealed class DelayedImportHintNameEntry : ImportHintNameEntryBase - { - internal DelayedImportHintNameEntry(PortableExecutableImage image, ulong offset, uint size, ushort entryHint, string entryName, bool isPadded) : base(image, offset, size, entryHint, entryName, isPadded, true) - { - } - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Workshell.PE.Content +{ + public sealed class DelayedImportHintNameEntry : ImportHintNameEntryBase + { + internal DelayedImportHintNameEntry(PortableExecutableImage image, long offset, uint size, ushort entryHint, string entryName, bool isPadded) : base(image, offset, size, entryHint, entryName, isPadded, true) + { + } + } +} diff --git a/src/Workshell.PE/Content/Imports/DelayedImportHintNameTable.cs b/src/Workshell.PE/Content/Imports/DelayedImportHintNameTable.cs index e9440a0..5a3200e 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportHintNameTable.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportHintNameTable.cs @@ -32,7 +32,7 @@ namespace Workshell.PE.Content { public sealed class DelayedImportHintNameTable : ImportHintNameTableBase { - internal DelayedImportHintNameTable(PortableExecutableImage image, DataDirectory dataDirectory, Location location, Tuple[] entries) : base(image, dataDirectory, location, entries, true) + internal DelayedImportHintNameTable(PortableExecutableImage image, DataDirectory dataDirectory, Location location, IEnumerable> entries) : base(image, dataDirectory, location, entries, true) { } @@ -43,7 +43,7 @@ public static async Task GetAsync(PortableExecutable if (directory == null) directory = await DelayedImportDirectory.GetAsync(image).ConfigureAwait(false); - var entries = new Dictionary>(); + var entries = new Dictionary>(); var ilt = await DelayedImportAddressTables.GetLookupTableAsync(image, directory).ConfigureAwait(false); var calc = image.GetCalculator(); var stream = image.GetStream(); @@ -52,11 +52,10 @@ public static async Task GetAsync(PortableExecutable { foreach (var entry in table) { - if (entry.Address == 0) - continue; - - if (entries.ContainsKey(entry.Address)) + if (entry.Address == 0 || entries.ContainsKey(entry.Address)) + { continue; + } if (!entry.IsOrdinal) { @@ -66,7 +65,7 @@ public static async Task GetAsync(PortableExecutable ushort hint = 0; var name = new StringBuilder(256); - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); hint = await stream.ReadUInt16Async().ConfigureAwait(false); size += sizeof(ushort); @@ -78,7 +77,9 @@ public static async Task GetAsync(PortableExecutable size++; if (b <= 0) + { break; + } name.Append((char)b); } @@ -89,7 +90,7 @@ public static async Task GetAsync(PortableExecutable size++; } - var tuple = new Tuple(offset, size, hint, name.ToString(), isPadded); + var tuple = new Tuple(offset, size, hint, name.ToString(), isPadded); entries.Add(entry.Address, tuple); } @@ -115,7 +116,7 @@ public static async Task GetAsync(PortableExecutable location = new Location(image, 0, 0, 0, 0, 0, null); } - var result = new DelayedImportHintNameTable(image, directory.DataDirectory, location, entries.Values.ToArray()); + var result = new DelayedImportHintNameTable(image, directory.DataDirectory, location, entries.Values); return result; } diff --git a/src/Workshell.PE/Content/Imports/DelayedImports.cs b/src/Workshell.PE/Content/Imports/DelayedImports.cs index 5087c5e..dbb41eb 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImports.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImports.cs @@ -86,7 +86,7 @@ public static async Task GetAsync(PortableExecutableImage image, var builder = new StringBuilder(256); var offset = calc.RVAToOffset(table.DirectoryEntry.Name); - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); while (true) { diff --git a/src/Workshell.PE/Content/Imports/ImportAddressTableBase.cs b/src/Workshell.PE/Content/Imports/ImportAddressTableBase.cs index 385f581..530d023 100644 --- a/src/Workshell.PE/Content/Imports/ImportAddressTableBase.cs +++ b/src/Workshell.PE/Content/Imports/ImportAddressTableBase.cs @@ -44,7 +44,7 @@ protected internal ImportAddressTableBase(PortableExecutableImage image, uint rv var imageBase = image.NTHeaders.OptionalHeader.ImageBase; var va = imageBase + rva; var offset = calc.RVAToOffset(rva); - var size = (entries.Length * (image.Is64Bit ? sizeof(ulong) : sizeof(uint))).ToUInt64(); + var size = (entries.Length * (image.Is64Bit ? sizeof(ulong) : sizeof(uint))); var section = calc.RVAToSection(rva); _image = image; @@ -82,7 +82,7 @@ public async Task GetBytesAsync() return buffer; } - private TEntry[] BuildEntries(PortableExecutableImage image, ulong tableOffset, ulong[] entries) + private TEntry[] BuildEntries(PortableExecutableImage image, long tableOffset, ulong[] entries) { var results = new TEntry[entries.Length]; var ctors = typeof(TEntry).GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); diff --git a/src/Workshell.PE/Content/Imports/ImportAddressTableEntry.cs b/src/Workshell.PE/Content/Imports/ImportAddressTableEntry.cs index 8f47325..dcba722 100644 --- a/src/Workshell.PE/Content/Imports/ImportAddressTableEntry.cs +++ b/src/Workshell.PE/Content/Imports/ImportAddressTableEntry.cs @@ -1,35 +1,35 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Workshell.PE.Content -{ - public sealed class ImportAddressTableEntry : ImportAddressTableEntryBase - { - internal ImportAddressTableEntry(PortableExecutableImage image, ulong entryOffset, ulong entryValue, uint entryAddress, ushort entryOrdinal, bool isOrdinal) : base(image, entryOffset, entryValue, entryAddress, entryOrdinal, isOrdinal, false) - { - } - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Workshell.PE.Content +{ + public sealed class ImportAddressTableEntry : ImportAddressTableEntryBase + { + internal ImportAddressTableEntry(PortableExecutableImage image, long entryOffset, ulong entryValue, uint entryAddress, ushort entryOrdinal, bool isOrdinal) : base(image, entryOffset, entryValue, entryAddress, entryOrdinal, isOrdinal, false) + { + } + } +} diff --git a/src/Workshell.PE/Content/Imports/ImportAddressTableEntryBase.cs b/src/Workshell.PE/Content/Imports/ImportAddressTableEntryBase.cs index 7e5cb17..7789050 100644 --- a/src/Workshell.PE/Content/Imports/ImportAddressTableEntryBase.cs +++ b/src/Workshell.PE/Content/Imports/ImportAddressTableEntryBase.cs @@ -32,7 +32,7 @@ public abstract class ImportAddressTableEntryBase : ISupportsLocation, ISupports { private readonly PortableExecutableImage _image; - protected internal ImportAddressTableEntryBase(PortableExecutableImage image, ulong entryOffset, ulong entryValue, uint entryAddress, ushort entryOrdinal, bool isOrdinal, bool isDelayed) + protected internal ImportAddressTableEntryBase(PortableExecutableImage image, long entryOffset, ulong entryValue, uint entryAddress, ushort entryOrdinal, bool isOrdinal, bool isDelayed) { _image = image; @@ -40,7 +40,7 @@ protected internal ImportAddressTableEntryBase(PortableExecutableImage image, ul var rva = calc.OffsetToRVA(entryOffset); var imageBase = image.NTHeaders.OptionalHeader.ImageBase; var va = imageBase + rva; - var size = (image.Is64Bit ? sizeof(ulong) : sizeof(uint)).ToUInt64(); + var size = (image.Is64Bit ? sizeof(ulong) : sizeof(uint)); Location = new Location(image, entryOffset, rva, va, size, size); Value = entryValue; diff --git a/src/Workshell.PE/Content/Imports/ImportAddressTables.cs b/src/Workshell.PE/Content/Imports/ImportAddressTables.cs index 41fa7b1..b77c1eb 100644 --- a/src/Workshell.PE/Content/Imports/ImportAddressTables.cs +++ b/src/Workshell.PE/Content/Imports/ImportAddressTables.cs @@ -67,7 +67,7 @@ private static async Task GetTableAsync(PortableExecutableI var entries = new List(); var offset = calc.RVAToOffset(thunk); - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); while (true) { @@ -76,7 +76,9 @@ private static async Task GetTableAsync(PortableExecutableI entries.Add(entry); if (entry == 0) + { break; + } } var table = new Tuple(thunk, entries.ToArray(), dirEntry); @@ -92,13 +94,13 @@ private static async Task GetTableAsync(PortableExecutableI var imageBase = image.NTHeaders.OptionalHeader.ImageBase; var va = imageBase + rva; var fileOffset = calc.RVAToOffset(rva); - var fileSize = 0ul; + var fileSize = 0L; foreach (var table in tables) { var size = table.Item2.Length * (!image.Is64Bit ? sizeof(uint) : sizeof(ulong)); - fileSize += size.ToUInt32(); + fileSize += size; } var section = calc.RVAToSection(rva); diff --git a/src/Workshell.PE/Content/Imports/ImportAddressTablesBase.cs b/src/Workshell.PE/Content/Imports/ImportAddressTablesBase.cs index 2240ea1..7d07e9a 100644 --- a/src/Workshell.PE/Content/Imports/ImportAddressTablesBase.cs +++ b/src/Workshell.PE/Content/Imports/ImportAddressTablesBase.cs @@ -1,81 +1,82 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; - -namespace Workshell.PE.Content -{ - public abstract class ImportAddressTablesBase : DataContent, IEnumerable - where TTable : ImportAddressTableBase - where TTableEntry : ImportAddressTableEntryBase - { - private readonly TTable[] _tables; - - protected internal ImportAddressTablesBase(PortableExecutableImage image, DataDirectory dataDirectory, Location location, Tuple[] tables, bool isDelayed) : base(image, dataDirectory, location) - { - _tables = new TTable[tables.Length]; - - var type = typeof(TTable); - var ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - var ctor = ctors.First(); - - for (var i = 0; i < tables.Length; i++) - { - var tuple = tables[i]; - var table = (TTable)ctor.Invoke(new object[] { image, tuple.Item1, tuple.Item2, tuple.Item3 }); - - _tables[i] = table; - } - - Count = _tables.Length; - IsDelayed = isDelayed; - } - - #region Methods - - public IEnumerator GetEnumerator() - { - foreach (var table in _tables) - yield return table; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - #endregion - - #region Properties - - public int Count { get; } - public TTable this[int index] => _tables[index]; - public bool IsDelayed { get; } - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Workshell.PE.Content +{ + public abstract class ImportAddressTablesBase : DataContent, IEnumerable + where TTable : ImportAddressTableBase + where TTableEntry : ImportAddressTableEntryBase + { + private readonly TTable[] _tables; + + protected internal ImportAddressTablesBase(PortableExecutableImage image, DataDirectory dataDirectory, Location location, IEnumerable> tables, bool isDelayed) : base(image, dataDirectory, location) + { + _tables = new TTable[tables.Count()]; + + var type = typeof(TTable); + var ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + var ctor = ctors.First(); + var idx = 0; + + foreach (var t in tables) + { + var table = (TTable)ctor.Invoke(new object[] { image, t.Item1, t.Item2, t.Item3 }); + + _tables[idx] = table; + idx++; + } + + Count = _tables.Length; + IsDelayed = isDelayed; + } + + #region Methods + + public IEnumerator GetEnumerator() + { + foreach (var table in _tables) + yield return table; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + #region Properties + + public int Count { get; } + public TTable this[int index] => _tables[index]; + public bool IsDelayed { get; } + + #endregion + } +} diff --git a/src/Workshell.PE/Content/Imports/ImportDirectory.cs b/src/Workshell.PE/Content/Imports/ImportDirectory.cs index 65a1248..7cce56e 100644 --- a/src/Workshell.PE/Content/Imports/ImportDirectory.cs +++ b/src/Workshell.PE/Content/Imports/ImportDirectory.cs @@ -48,37 +48,43 @@ public static ImportDirectory Get(PortableExecutableImage image) public static async Task GetAsync(PortableExecutableImage image) { if (!image.NTHeaders.DataDirectories.Exists(DataDirectoryType.ImportTable)) + { return null; + } DataDirectory dataDirectory = image.NTHeaders.DataDirectories[DataDirectoryType.ImportTable]; if (DataDirectory.IsNullOrEmpty(dataDirectory)) + { return null; + } var calc = image.GetCalculator(); var section = calc.RVAToSection(dataDirectory.VirtualAddress); var fileOffset = calc.RVAToOffset(section, dataDirectory.VirtualAddress); var stream = image.GetStream(); - stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(fileOffset, SeekOrigin.Begin); var size = Utils.SizeOf(); - var descriptors = new List>(); + var descriptors = new List>(); try { - ulong offset = 0; + var offset = 0L; while (true) { var descriptor = await stream.ReadStructAsync(size).ConfigureAwait(false); if (descriptor.OriginalFirstThunk == 0 && descriptor.FirstThunk == 0) + { break; + } - var tuple = new Tuple(offset, descriptor); + var tuple = new Tuple(offset, descriptor); - offset += size.ToUInt32(); + offset += size; descriptors.Add(tuple); } diff --git a/src/Workshell.PE/Content/Imports/ImportDirectoryBase.cs b/src/Workshell.PE/Content/Imports/ImportDirectoryBase.cs index 58b9068..f17b348 100644 --- a/src/Workshell.PE/Content/Imports/ImportDirectoryBase.cs +++ b/src/Workshell.PE/Content/Imports/ImportDirectoryBase.cs @@ -1,82 +1,82 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Threading.Tasks; - -using Workshell.PE.Extensions; - -namespace Workshell.PE.Content -{ - public abstract class ImportDirectoryBase : DataContent, IEnumerable where T : ImportDirectoryEntryBase - { - private readonly T[] _entries; - - protected internal ImportDirectoryBase(PortableExecutableImage image, DataDirectory dataDirectory, Location location, T[] entries) : base(image, dataDirectory, location) - { - _entries = entries; - - Count = _entries.Length; - } - - #region Static Methods - - protected internal static async Task GetNameAsync(LocationCalculator calc, Stream stream, uint nameRVA) - { - var fileOffset = calc.RVAToOffset(nameRVA); - - stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin); - - var result = await stream.ReadStringAsync().ConfigureAwait(false); - - return result; - } - - #endregion - - #region Methods - - public IEnumerator GetEnumerator() - { - foreach(var entry in _entries) - yield return entry; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - #endregion - - #region Properties - - public int Count { get; } - public T this[int index] => _entries[index]; - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +using Workshell.PE.Extensions; + +namespace Workshell.PE.Content +{ + public abstract class ImportDirectoryBase : DataContent, IEnumerable where T : ImportDirectoryEntryBase + { + private readonly T[] _entries; + + protected internal ImportDirectoryBase(PortableExecutableImage image, DataDirectory dataDirectory, Location location, T[] entries) : base(image, dataDirectory, location) + { + _entries = entries; + + Count = _entries.Length; + } + + #region Static Methods + + protected internal static async Task GetNameAsync(LocationCalculator calc, Stream stream, uint nameRVA) + { + var fileOffset = calc.RVAToOffset(nameRVA); + + stream.Seek(fileOffset, SeekOrigin.Begin); + + var result = await stream.ReadStringAsync().ConfigureAwait(false); + + return result; + } + + #endregion + + #region Methods + + public IEnumerator GetEnumerator() + { + foreach(var entry in _entries) + yield return entry; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + #region Properties + + public int Count { get; } + public T this[int index] => _entries[index]; + + #endregion + } +} diff --git a/src/Workshell.PE/Content/Imports/ImportHintNameEntry.cs b/src/Workshell.PE/Content/Imports/ImportHintNameEntry.cs index 50b4e97..52a73c6 100644 --- a/src/Workshell.PE/Content/Imports/ImportHintNameEntry.cs +++ b/src/Workshell.PE/Content/Imports/ImportHintNameEntry.cs @@ -1,35 +1,35 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Workshell.PE.Content -{ - public sealed class ImportHintNameEntry : ImportHintNameEntryBase - { - internal ImportHintNameEntry(PortableExecutableImage image, ulong offset, uint size, ushort entryHint, string entryName, bool isPadded) : base(image, offset, size, entryHint, entryName, isPadded, false) - { - } - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Workshell.PE.Content +{ + public sealed class ImportHintNameEntry : ImportHintNameEntryBase + { + internal ImportHintNameEntry(PortableExecutableImage image, long offset, uint size, ushort entryHint, string entryName, bool isPadded) : base(image, offset, size, entryHint, entryName, isPadded, false) + { + } + } +} diff --git a/src/Workshell.PE/Content/Imports/ImportHintNameEntryBase.cs b/src/Workshell.PE/Content/Imports/ImportHintNameEntryBase.cs index 9707603..e3812bf 100644 --- a/src/Workshell.PE/Content/Imports/ImportHintNameEntryBase.cs +++ b/src/Workshell.PE/Content/Imports/ImportHintNameEntryBase.cs @@ -32,7 +32,7 @@ public abstract class ImportHintNameEntryBase : ISupportsLocation, ISupportsByte { private readonly PortableExecutableImage _image; - protected internal ImportHintNameEntryBase(PortableExecutableImage image, ulong offset, uint size, ushort entryHint, string entryName, bool isPadded, bool isDelayed) + protected internal ImportHintNameEntryBase(PortableExecutableImage image, long offset, uint size, ushort entryHint, string entryName, bool isPadded, bool isDelayed) { _image = image; diff --git a/src/Workshell.PE/Content/Imports/ImportHintNameTable.cs b/src/Workshell.PE/Content/Imports/ImportHintNameTable.cs index 6b1d6f4..b6c3505 100644 --- a/src/Workshell.PE/Content/Imports/ImportHintNameTable.cs +++ b/src/Workshell.PE/Content/Imports/ImportHintNameTable.cs @@ -32,7 +32,7 @@ namespace Workshell.PE.Content { public sealed class ImportHintNameTable : ImportHintNameTableBase { - internal ImportHintNameTable(PortableExecutableImage image, DataDirectory dataDirectory, Location location, Tuple[] entries) : base(image, dataDirectory, location, entries, false) + internal ImportHintNameTable(PortableExecutableImage image, DataDirectory dataDirectory, Location location, IEnumerable> entries) : base(image, dataDirectory, location, entries, false) { } @@ -41,9 +41,11 @@ internal ImportHintNameTable(PortableExecutableImage image, DataDirectory dataDi public static async Task GetAsync(PortableExecutableImage image, ImportDirectory directory = null) { if (directory == null) + { directory = await ImportDirectory.GetAsync(image).ConfigureAwait(false); + } - var entries = new Dictionary>(); + var entries = new Dictionary>(); var ilt = await ImportAddressTables.GetLookupTableAsync(image, directory).ConfigureAwait(false); var calc = image.GetCalculator(); var stream = image.GetStream(); @@ -52,11 +54,10 @@ public static async Task GetAsync(PortableExecutableImage i { foreach (var entry in table) { - if (entry.Address == 0) - continue; - - if (entries.ContainsKey(entry.Address)) + if (entry.Address == 0 || entries.ContainsKey(entry.Address)) + { continue; + } if (!entry.IsOrdinal) { @@ -66,7 +67,7 @@ public static async Task GetAsync(PortableExecutableImage i ushort hint = 0; var name = new StringBuilder(256); - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); hint = await stream.ReadUInt16Async().ConfigureAwait(false); size += sizeof(ushort); @@ -78,7 +79,9 @@ public static async Task GetAsync(PortableExecutableImage i size++; if (b <= 0) + { break; + } name.Append((char)b); } @@ -89,7 +92,7 @@ public static async Task GetAsync(PortableExecutableImage i size++; } - var tuple = new Tuple(offset, size, hint, name.ToString(), isPadded); + var tuple = new Tuple(offset, size, hint, name.ToString(), isPadded); entries.Add(entry.Address, tuple); } diff --git a/src/Workshell.PE/Content/Imports/ImportHintNameTableBase.cs b/src/Workshell.PE/Content/Imports/ImportHintNameTableBase.cs index a075499..96cc87c 100644 --- a/src/Workshell.PE/Content/Imports/ImportHintNameTableBase.cs +++ b/src/Workshell.PE/Content/Imports/ImportHintNameTableBase.cs @@ -1,90 +1,93 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace Workshell.PE.Content -{ - public abstract class ImportHintNameTableBase : DataContent, IEnumerable - where TEntry : ImportHintNameEntryBase - { - private readonly TEntry[] _entries; - - protected internal ImportHintNameTableBase(PortableExecutableImage image, DataDirectory dataDirectory, Location location, Tuple[] entries, bool isDelayed) : base(image, dataDirectory, location) - { - _entries = BuildTable(entries); - - Count = _entries.Length; - IsDelayed = isDelayed; - } - - #region Methods - - public override string ToString() - { - return $"File Offset: 0x{Location.FileOffset:X8}, Name Count: {_entries.Length}"; - } - - public IEnumerator GetEnumerator() - { - foreach (var entry in _entries) - yield return entry; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - private TEntry[] BuildTable(Tuple[] entries) - { - TEntry[] results = new TEntry[entries.Length]; - - var type = typeof(TEntry); - var ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - var ctor = ctors.First(); - - for(var i = 0; i < entries.Length; i++) - { - var entry = (TEntry)ctor.Invoke(new object[] { Image, entries[i].Item1, entries[i].Item2, entries[i].Item3, entries[i].Item4, entries[i].Item5 }); - - results[i] = entry; - } - - return results.OrderBy(entry => entry.Location.FileOffset).ToArray(); - } - - #endregion - - #region Properties - - public int Count { get; } - public TEntry this[int index] => _entries[index]; - public bool IsDelayed { get; } - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Reflection; + +namespace Workshell.PE.Content +{ + public abstract class ImportHintNameTableBase : DataContent, IEnumerable + where TEntry : ImportHintNameEntryBase + { + private readonly TEntry[] _entries; + + protected internal ImportHintNameTableBase(PortableExecutableImage image, DataDirectory dataDirectory, Location location, IEnumerable> entries, bool isDelayed) : base(image, dataDirectory, location) + { + _entries = BuildTable(entries); + + Count = _entries.Length; + IsDelayed = isDelayed; + } + + #region Methods + + public override string ToString() + { + return $"File Offset: 0x{Location.FileOffset:X8}, Name Count: {_entries.Length}"; + } + + public IEnumerator GetEnumerator() + { + foreach (var entry in _entries) + { + yield return entry; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + private TEntry[] BuildTable(IEnumerable> entries) + { + var results = new List(entries.Count()); + var type = typeof(TEntry); + var ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + var ctor = ctors.First(); + + foreach (var e in entries) + { + var entry = (TEntry)ctor.Invoke(new object[] { Image, e.Item1, e.Item2, e.Item3, e.Item4, e.Item5 }); + + results.Add(entry); + } + + return results.OrderBy(entry => entry.Location.FileOffset) + .ToArray(); + } + + #endregion + + #region Properties + + public int Count { get; } + public TEntry this[int index] => _entries[index]; + public bool IsDelayed { get; } + + #endregion + } +} diff --git a/src/Workshell.PE/Content/Imports/Imports.cs b/src/Workshell.PE/Content/Imports/Imports.cs index 42aa75f..fbe9232 100644 --- a/src/Workshell.PE/Content/Imports/Imports.cs +++ b/src/Workshell.PE/Content/Imports/Imports.cs @@ -86,7 +86,7 @@ public static async Task GetAsync(PortableExecutableImage image, Import var builder = new StringBuilder(256); var offset = calc.RVAToOffset(table.DirectoryEntry.Name); - stream.Seek(offset.ToInt64(), SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); while (true) { diff --git a/src/Workshell.PE/Content/LoadConfigurationDirectory.cs b/src/Workshell.PE/Content/LoadConfigurationDirectory.cs index 4887b7c..14ff7d2 100644 --- a/src/Workshell.PE/Content/LoadConfigurationDirectory.cs +++ b/src/Workshell.PE/Content/LoadConfigurationDirectory.cs @@ -179,7 +179,7 @@ public static async Task GetAsync(PortableExecutable var location = new Location(image, fileOffset, dataDirectory.VirtualAddress, imageBase + dataDirectory.VirtualAddress, dataDirectory.Size, dataDirectory.Size, section); var stream = image.GetStream(); - stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(fileOffset, SeekOrigin.Begin); LoadConfigurationDirectory directory = null; diff --git a/src/Workshell.PE/Content/Relocation/RelocationTable.cs b/src/Workshell.PE/Content/Relocation/RelocationTable.cs index e0f02be..620e731 100644 --- a/src/Workshell.PE/Content/Relocation/RelocationTable.cs +++ b/src/Workshell.PE/Content/Relocation/RelocationTable.cs @@ -66,7 +66,7 @@ public static async Task GetAsync(PortableExecutableImage image var location = new Location(image, fileOffset, dataDirectory.VirtualAddress, imageBase + dataDirectory.VirtualAddress, dataDirectory.Size, dataDirectory.Size, section); var stream = image.GetStream(); - stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(fileOffset, SeekOrigin.Begin); var blockOffset = fileOffset; var blockSize = 0u; diff --git a/src/Workshell.PE/Content/Resources/ResourceDataEntry.cs b/src/Workshell.PE/Content/Resources/ResourceDataEntry.cs index 64e9695..e616a57 100644 --- a/src/Workshell.PE/Content/Resources/ResourceDataEntry.cs +++ b/src/Workshell.PE/Content/Resources/ResourceDataEntry.cs @@ -68,7 +68,7 @@ internal async Task LoadAsync() { var stream = Image.GetStream(); - stream.Seek(Location.FileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(Location.FileOffset, SeekOrigin.Begin); try { diff --git a/src/Workshell.PE/Content/Resources/ResourceDirectory.cs b/src/Workshell.PE/Content/Resources/ResourceDirectory.cs index 75a2596..c78095c 100644 --- a/src/Workshell.PE/Content/Resources/ResourceDirectory.cs +++ b/src/Workshell.PE/Content/Resources/ResourceDirectory.cs @@ -108,7 +108,7 @@ internal async Task LoadAsync() var calc = Image.GetCalculator(); var stream = Image.GetStream(); - stream.Seek(Location.FileOffset.ToInt64(),SeekOrigin.Begin); + stream.Seek(Location.FileOffset,SeekOrigin.Begin); var directorySize = Utils.SizeOf(); IMAGE_RESOURCE_DIRECTORY directory; @@ -129,7 +129,7 @@ internal async Task LoadAsync() for (int i = 0; i < count; i++) { - stream.Seek(offset.ToInt64(),SeekOrigin.Begin); + stream.Seek(offset,SeekOrigin.Begin); var entry = await stream.ReadStructAsync(entrySize).ConfigureAwait(false); var rva = calc.OffsetToRVA(offset); diff --git a/src/Workshell.PE/Content/Resources/ResourceDirectoryEntry.cs b/src/Workshell.PE/Content/Resources/ResourceDirectoryEntry.cs index 4e2422d..7e080a9 100644 --- a/src/Workshell.PE/Content/Resources/ResourceDirectoryEntry.cs +++ b/src/Workshell.PE/Content/Resources/ResourceDirectoryEntry.cs @@ -93,7 +93,7 @@ public async Task GetNameAsync() var rva = DataDirectory.VirtualAddress + offset; var fileOffset = calc.RVAToOffset(rva); - stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(fileOffset, SeekOrigin.Begin); var count = await stream.ReadUInt16Async().ConfigureAwait(false); var builder = new StringBuilder(count); diff --git a/src/Workshell.PE/Content/TLSDirectory.cs b/src/Workshell.PE/Content/TLSDirectory.cs index c9d226c..ba789a0 100644 --- a/src/Workshell.PE/Content/TLSDirectory.cs +++ b/src/Workshell.PE/Content/TLSDirectory.cs @@ -82,7 +82,7 @@ public static async Task GetAsync(PortableExecutableImage image) var location = new Location(image, fileOffset, dataDirectory.VirtualAddress, imageBase + dataDirectory.VirtualAddress, dataDirectory.Size, dataDirectory.Size, section); var stream = image.GetStream(); - stream.Seek(fileOffset.ToInt64(), SeekOrigin.Begin); + stream.Seek(fileOffset, SeekOrigin.Begin); TLSDirectory directory = null; diff --git a/src/Workshell.PE/DataDirectories.cs b/src/Workshell.PE/DataDirectories.cs index 327797e..0b112fd 100644 --- a/src/Workshell.PE/DataDirectories.cs +++ b/src/Workshell.PE/DataDirectories.cs @@ -44,7 +44,7 @@ internal DataDirectories(PortableExecutableImage image, OptionalHeader optHeader var fileSize = optHeader.Location.FileSize; var fileOffset = optHeader.Location.FileOffset + fileSize; var rva = optHeader.Location.RelativeVirtualAddress + optHeader.Location.VirtualSize.ToUInt32(); - var va = optHeader.Location.VirtualAddress + optHeader.Location.VirtualSize; + var va = optHeader.Location.VirtualAddress + optHeader.Location.VirtualSize.ToUInt64(); Location = new Location(image, fileOffset, rva, va, size, size); @@ -55,7 +55,9 @@ internal DataDirectories(PortableExecutableImage image, OptionalHeader optHeader var type = DataDirectoryType.Unknown; if (i >= 0 && i <= 14) - type = (DataDirectoryType)i; + { + type = (DataDirectoryType) i; + } var dir = new DataDirectory(image,this,type,dataDirs[i],optHeader.ImageBase); diff --git a/src/Workshell.PE/Extensions/Stream.cs b/src/Workshell.PE/Extensions/Stream.cs index 5921f51..6c2174b 100644 --- a/src/Workshell.PE/Extensions/Stream.cs +++ b/src/Workshell.PE/Extensions/Stream.cs @@ -1,320 +1,322 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace Workshell.PE.Extensions -{ - internal static class StreamExtensions - { - #region Methods - - public static async Task ReadStructAsync(this Stream stream) where T : struct - { - var size = Utils.SizeOf(); - - return await ReadStructAsync(stream, size).ConfigureAwait(false); - } - - public static async Task ReadStructAsync(this Stream stream, int size, bool allowSmaller = false) where T : struct - { - var buffer = new byte[size]; - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - - if (!allowSmaller && numRead < size) - throw new IOException("Could not read all of structure from stream."); - - if (numRead < size) - return default(T); - - return Utils.Read(buffer); - } - - public static async Task ReadByteAsync(this Stream stream) - { - var buffer = new byte[1]; - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - - if (numRead < 1) - throw new IOException("Could not read byte from stream."); - - return buffer[0]; - } - - public static async Task ReadInt16Async(this Stream stream) - { - var buffer = new byte[sizeof(short)]; - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - - if (numRead < buffer.Length) - throw new IOException("Could not read int16 from stream."); - - return Utils.ReadInt16(buffer); - } - - public static async Task ReadInt32Async(this Stream stream) - { - var buffer = new byte[sizeof(int)]; - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - - if (numRead < buffer.Length) - throw new IOException("Could not read int32 from stream."); - - return Utils.ReadInt32(buffer); - } - - public static async Task ReadInt64Async(this Stream stream) - { - var buffer = new byte[sizeof(long)]; - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - - if (numRead < buffer.Length) - throw new IOException("Could not read int64 from stream."); - - return Utils.ReadInt64(buffer); - } - - public static async Task ReadUInt16Async(this Stream stream) - { - var buffer = new byte[sizeof(ushort)]; - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - - if (numRead < buffer.Length) - throw new IOException("Could not read uint16 from stream."); - - return Utils.ReadUInt16(buffer); - } - - public static async Task ReadUInt32Async(this Stream stream) - { - var buffer = new byte[sizeof(uint)]; - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - - if (numRead < buffer.Length) - throw new IOException("Could not read uint32 from stream."); - - return Utils.ReadUInt32(buffer); - } - - public static async Task ReadUInt64Async(this Stream stream) - { - var buffer = new byte[sizeof(ulong)]; - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - - if (numRead < buffer.Length) - throw new IOException("Could not read uint64 from stream."); - - return Utils.ReadUInt64(buffer); - } - - public static async Task ReadStringAsync(this Stream stream) - { - var builder = new StringBuilder(256); - var buffer = new byte[1]; - - while (true) - { - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length); - - if (numRead < 1 || buffer[0] == 0) - break; - - builder.Append((char) buffer[0]); - } - - return builder.ToString(); - } - - public static async Task ReadStringAsync(this Stream stream, int size, bool allowSmaller = true) - { - var buffer = new byte[size]; - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length); - - if (!allowSmaller && numRead < buffer.Length) - throw new IOException("Could not read string from stream."); - - var builder = new StringBuilder(256); - - foreach(var b in buffer) - { - if (b == 0) - break; - - builder.Append((char)b); - } - - return builder.ToString(); - } - - public static async Task ReadUnicodeStringAsync(this Stream stream) - { - var builder = new StringBuilder(); - - while (true) - { - var value = await ReadUInt16Async(stream).ConfigureAwait(false); - - if (value == 0) - break; - - builder.Append((char)value); - } - - return builder.ToString(); - } - - public static async Task ReadUnicodeStringAsync(this Stream stream, int charCount) - { - var builder = new StringBuilder(); - - for(var i = 0; i < charCount; i++) - { - var value = await ReadUInt16Async(stream).ConfigureAwait(false); - - if (value == 0) - break; - - builder.Append((char)value); - } - - return builder.ToString(); - } - - public static async Task ReadBytesAsync(this Stream stream, int count, long offset = -1) - { - if (offset >= 0) - stream.Seek(offset, SeekOrigin.Begin); - - var buffer = new byte[count]; - var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - var results = new byte[numRead]; - - Array.Copy(buffer, 0, results, 0, numRead); - - return results; - } - - public static async Task ReadBytesAsync(this Stream stream, Location location) - { - return await ReadBytesAsync(stream, location.FileSize.ToInt32(), location.FileOffset.ToInt64()) - .ConfigureAwait(false); - } - - public static async Task SkipBytesAsync(this Stream stream, int count) - { - var buffer = new byte[count]; - - return await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - } - - public static async Task WriteBytesAsync(this Stream stream, byte[] bytes) - { - await stream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); - } - - public static async Task WriteByteAsync(this Stream stream, byte value) - { - var buffer = new[] { value }; - - await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - } - - public static async Task WriteInt16Async(this Stream stream, short value) - { - var buffer = BitConverter.GetBytes(value); - - await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - } - - public static async Task WriteInt32Async(this Stream stream, int value) - { - var buffer = BitConverter.GetBytes(value); - - await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - } - - public static async Task WriteInt64Async(this Stream stream, long value) - { - var buffer = BitConverter.GetBytes(value); - - await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - } - - public static async Task WriteUInt16Async(this Stream stream, ushort value) - { - var buffer = BitConverter.GetBytes(value); - - await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - } - - public static async Task WriteUInt32Async(this Stream stream, uint value) - { - var buffer = BitConverter.GetBytes(value); - - await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - } - - public static async Task WriteUInt64Async(this Stream stream, ulong value) - { - var buffer = BitConverter.GetBytes(value); - - await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - } - - public static async Task WriteStructAsync(this Stream stream, T structure) where T : struct - { - var size = Utils.SizeOf(); - - await WriteStructAsync(stream, structure, size).ConfigureAwait(false); - } - - public static async Task WriteStructAsync(this Stream stream, T structure, int size) where T : struct - { - var buffer = new byte[size]; - - WriteStruct(structure,buffer,0,buffer.Length); - await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - } - - private static void WriteStruct(T structure, byte[] buffer, int startIndex, int count) where T : struct - { - var ptr = Marshal.AllocHGlobal(count); - - try - { - Marshal.StructureToPtr(structure,ptr,false); - Marshal.Copy(ptr,buffer,startIndex,count); - } - finally - { - Marshal.FreeHGlobal(ptr); - } - } - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Workshell.PE.Extensions +{ + internal static class StreamExtensions + { + #region Methods + + public static async Task ReadStructAsync(this Stream stream) where T : struct + { + var size = Utils.SizeOf(); + + return await ReadStructAsync(stream, size).ConfigureAwait(false); + } + + public static async Task ReadStructAsync(this Stream stream, int size, bool allowSmaller = false) where T : struct + { + var buffer = new byte[size]; + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + + if (!allowSmaller && numRead < size) + throw new IOException("Could not read all of structure from stream."); + + if (numRead < size) + return default(T); + + return Utils.Read(buffer); + } + + public static async Task ReadByteAsync(this Stream stream) + { + var buffer = new byte[1]; + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + + if (numRead < 1) + { + throw new IOException("Could not read byte from stream."); + } + + return buffer[0]; + } + + public static async Task ReadInt16Async(this Stream stream) + { + var buffer = new byte[sizeof(short)]; + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + + if (numRead < buffer.Length) + throw new IOException("Could not read int16 from stream."); + + return Utils.ReadInt16(buffer); + } + + public static async Task ReadInt32Async(this Stream stream) + { + var buffer = new byte[sizeof(int)]; + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + + if (numRead < buffer.Length) + throw new IOException("Could not read int32 from stream."); + + return Utils.ReadInt32(buffer); + } + + public static async Task ReadInt64Async(this Stream stream) + { + var buffer = new byte[sizeof(long)]; + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + + if (numRead < buffer.Length) + throw new IOException("Could not read int64 from stream."); + + return Utils.ReadInt64(buffer); + } + + public static async Task ReadUInt16Async(this Stream stream) + { + var buffer = new byte[sizeof(ushort)]; + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + + if (numRead < buffer.Length) + throw new IOException("Could not read uint16 from stream."); + + return Utils.ReadUInt16(buffer); + } + + public static async Task ReadUInt32Async(this Stream stream) + { + var buffer = new byte[sizeof(uint)]; + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + + if (numRead < buffer.Length) + throw new IOException("Could not read uint32 from stream."); + + return Utils.ReadUInt32(buffer); + } + + public static async Task ReadUInt64Async(this Stream stream) + { + var buffer = new byte[sizeof(ulong)]; + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + + if (numRead < buffer.Length) + throw new IOException("Could not read uint64 from stream."); + + return Utils.ReadUInt64(buffer); + } + + public static async Task ReadStringAsync(this Stream stream) + { + var builder = new StringBuilder(256); + var buffer = new byte[1]; + + while (true) + { + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length); + + if (numRead < 1 || buffer[0] == 0) + break; + + builder.Append((char) buffer[0]); + } + + return builder.ToString(); + } + + public static async Task ReadStringAsync(this Stream stream, int size, bool allowSmaller = true) + { + var buffer = new byte[size]; + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length); + + if (!allowSmaller && numRead < buffer.Length) + throw new IOException("Could not read string from stream."); + + var builder = new StringBuilder(256); + + foreach(var b in buffer) + { + if (b == 0) + break; + + builder.Append((char)b); + } + + return builder.ToString(); + } + + public static async Task ReadUnicodeStringAsync(this Stream stream) + { + var builder = new StringBuilder(); + + while (true) + { + var value = await ReadUInt16Async(stream).ConfigureAwait(false); + + if (value == 0) + break; + + builder.Append((char)value); + } + + return builder.ToString(); + } + + public static async Task ReadUnicodeStringAsync(this Stream stream, int charCount) + { + var builder = new StringBuilder(); + + for(var i = 0; i < charCount; i++) + { + var value = await ReadUInt16Async(stream).ConfigureAwait(false); + + if (value == 0) + break; + + builder.Append((char)value); + } + + return builder.ToString(); + } + + public static async Task ReadBytesAsync(this Stream stream, int count, long offset = -1) + { + if (offset >= 0) + stream.Seek(offset, SeekOrigin.Begin); + + var buffer = new byte[count]; + var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + var results = new byte[numRead]; + + Array.Copy(buffer, 0, results, 0, numRead); + + return results; + } + + public static async Task ReadBytesAsync(this Stream stream, Location location) + { + return await ReadBytesAsync(stream, location.FileSize.ToInt32(), location.FileOffset) + .ConfigureAwait(false); + } + + public static async Task SkipBytesAsync(this Stream stream, int count) + { + var buffer = new byte[count]; + + return await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + } + + public static async Task WriteBytesAsync(this Stream stream, byte[] bytes) + { + await stream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); + } + + public static async Task WriteByteAsync(this Stream stream, byte value) + { + var buffer = new[] { value }; + + await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + } + + public static async Task WriteInt16Async(this Stream stream, short value) + { + var buffer = BitConverter.GetBytes(value); + + await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + } + + public static async Task WriteInt32Async(this Stream stream, int value) + { + var buffer = BitConverter.GetBytes(value); + + await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + } + + public static async Task WriteInt64Async(this Stream stream, long value) + { + var buffer = BitConverter.GetBytes(value); + + await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + } + + public static async Task WriteUInt16Async(this Stream stream, ushort value) + { + var buffer = BitConverter.GetBytes(value); + + await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + } + + public static async Task WriteUInt32Async(this Stream stream, uint value) + { + var buffer = BitConverter.GetBytes(value); + + await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + } + + public static async Task WriteUInt64Async(this Stream stream, ulong value) + { + var buffer = BitConverter.GetBytes(value); + + await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + } + + public static async Task WriteStructAsync(this Stream stream, T structure) where T : struct + { + var size = Utils.SizeOf(); + + await WriteStructAsync(stream, structure, size).ConfigureAwait(false); + } + + public static async Task WriteStructAsync(this Stream stream, T structure, int size) where T : struct + { + var buffer = new byte[size]; + + WriteStruct(structure,buffer,0,buffer.Length); + await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false); + } + + private static void WriteStruct(T structure, byte[] buffer, int startIndex, int count) where T : struct + { + var ptr = Marshal.AllocHGlobal(count); + + try + { + Marshal.StructureToPtr(structure,ptr,false); + Marshal.Copy(ptr,buffer,startIndex,count); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + } + + #endregion + } +} diff --git a/src/Workshell.PE/PortableExecutableImage.cs b/src/Workshell.PE/PortableExecutableImage.cs index bb036e0..768d1c0 100644 --- a/src/Workshell.PE/PortableExecutableImage.cs +++ b/src/Workshell.PE/PortableExecutableImage.cs @@ -160,7 +160,7 @@ private async Task LoadAsync() try { - dosHeader = await _stream.ReadStructAsync(DOSHeader.Size).ConfigureAwait(false); + dosHeader = await _stream.ReadStructAsync(DOSHeader.Size.ToInt32()).ConfigureAwait(false); } catch (Exception ex) { @@ -194,7 +194,7 @@ private async Task LoadAsync() var stubOffset = DOSHeader.Size; var stubSize = dosHeader.e_lfanew - DOSHeader.Size; - var stubRead = await _stream.SkipBytesAsync(stubSize).ConfigureAwait(false); + var stubRead = await _stream.SkipBytesAsync(stubSize.ToInt32()).ConfigureAwait(false); if (stubRead < stubSize) { @@ -203,7 +203,7 @@ private async Task LoadAsync() _stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); - var ntOffset = _stream.Position; + var ntOffset = _stream.Position.ToUInt32(); uint peSig; try @@ -265,18 +265,16 @@ private async Task LoadAsync() IMAGE_OPTIONAL_HEADER32 optionalHeader32 = new IMAGE_OPTIONAL_HEADER32(); IMAGE_OPTIONAL_HEADER64 optionalHeader64 = new IMAGE_OPTIONAL_HEADER64(); - var dirCount = 0; + int dirCount; if (Is32Bit) { optionalHeader32 = Utils.Read(optionalHeaderBytes); - dirCount = optionalHeader32.NumberOfRvaAndSizes.ToInt32(); } else { optionalHeader64 = Utils.Read(optionalHeaderBytes); - dirCount = optionalHeader64.NumberOfRvaAndSizes.ToInt32(); } @@ -341,24 +339,24 @@ private async Task LoadAsync() var imageBase = (Is32Bit ? optionalHeader32.ImageBase : optionalHeader64.ImageBase); DOSHeader = new DOSHeader(this, dosHeader, imageBase); - DOSStub = new DOSStub(this, stubOffset.ToUInt64(), stubSize.ToUInt32(), imageBase); + DOSStub = new DOSStub(this, stubOffset, stubSize, imageBase); - var fileHeader = new FileHeader(this, fileHdr, DOSStub.Location.FileOffset + DOSStub.Location.FileSize + 4, imageBase); + var fileHeader = new FileHeader(this, fileHdr, (DOSStub.Location.FileOffset + DOSStub.Location.FileSize + 4).ToUInt32(), imageBase); OptionalHeader optionalHeader; if (Is32Bit) { - optionalHeader = new OptionalHeader32(this, optionalHeader32, fileHeader.Location.FileOffset + fileHeader.Location.FileSize, imageBase, magic); + optionalHeader = new OptionalHeader32(this, optionalHeader32, (fileHeader.Location.FileOffset + fileHeader.Location.FileSize).ToUInt32(), imageBase, magic); } else { - optionalHeader = new OptionalHeader64(this, optionalHeader64, fileHeader.Location.FileOffset + fileHeader.Location.FileSize, imageBase, magic); + optionalHeader = new OptionalHeader64(this, optionalHeader64, (fileHeader.Location.FileOffset + fileHeader.Location.FileSize).ToUInt32(), imageBase, magic); } var dataDirectories = new DataDirectories(this, optionalHeader, dataDirs); - NTHeaders = new NTHeaders(this, ntOffset.ToUInt64(), imageBase, fileHeader, optionalHeader, dataDirectories); - SectionTable = new SectionTable(this, sectionTable, NTHeaders.Location.FileOffset + NTHeaders.Location.FileSize, imageBase); + NTHeaders = new NTHeaders(this, ntOffset, imageBase, fileHeader, optionalHeader, dataDirectories); + SectionTable = new SectionTable(this, sectionTable, (NTHeaders.Location.FileOffset + NTHeaders.Location.FileSize).ToUInt32(), imageBase); Sections = new Sections(this, SectionTable); } From bc88145dc689545dd739562bea80b0bb00011dfe Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Fri, 11 Oct 2019 14:15:49 +0100 Subject: [PATCH 02/12] Added null check for Export names, should be empty not null. --- src/Workshell.PE/Content/Exports/Export.cs | 136 ++++++++++----------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/src/Workshell.PE/Content/Exports/Export.cs b/src/Workshell.PE/Content/Exports/Export.cs index ea3520a..df29f24 100644 --- a/src/Workshell.PE/Content/Exports/Export.cs +++ b/src/Workshell.PE/Content/Exports/Export.cs @@ -1,68 +1,68 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Workshell.PE.Content -{ - public sealed class Export - { - internal Export(uint entryPoint, string name, uint ord, string forwardName) - { - EntryPoint = entryPoint; - Name = name; - Ordinal = ord; - ForwardName = forwardName; - } - - #region Methods - - public override string ToString() - { - string result; - - if (string.IsNullOrWhiteSpace(ForwardName)) - { - result = $"0x{EntryPoint:X8} {Ordinal:D4} {Name}"; - } - else - { - result = $"0x{EntryPoint:X8} {Ordinal:D4} {Name} -> {ForwardName}"; - } - - return result; - } - - #endregion - - #region Properties - - public uint EntryPoint { get; } - public string Name { get; } - public uint Ordinal { get; } - public string ForwardName { get; } - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Workshell.PE.Content +{ + public sealed class Export + { + internal Export(uint entryPoint, string name, uint ord, string forwardName) + { + EntryPoint = entryPoint; + Name = name ?? string.Empty; + Ordinal = ord; + ForwardName = forwardName ?? string.Empty; + } + + #region Methods + + public override string ToString() + { + string result; + + if (string.IsNullOrWhiteSpace(ForwardName)) + { + result = $"0x{EntryPoint:X8} {Ordinal:D4} {Name}"; + } + else + { + result = $"0x{EntryPoint:X8} {Ordinal:D4} {Name} -> {ForwardName}"; + } + + return result; + } + + #endregion + + #region Properties + + public uint EntryPoint { get; } + public string Name { get; } + public uint Ordinal { get; } + public string ForwardName { get; } + + #endregion + } +} From 13a6bb08da6875b82e4251e9e3699b81aca97a14 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Tue, 5 Nov 2019 23:44:51 +0000 Subject: [PATCH 03/12] Lots of work coming out of PEI. --- Src/Workshell.PE/Content/CLR/CLRHeader.cs | 8 +- Src/Workshell.PE/Location.cs | 1 - Src/Workshell.PE/SectionTable.cs | 15 + .../Content/Debug/DebugDirectoryEntry.cs | 1 - .../Content/Exports/ExportTable.cs | 27 ++ .../Imports/DelayedImportAddressTable.cs | 73 ++-- .../Imports/DelayedImportAddressTables.cs | 40 +- .../Imports/DelayedImportDirectoryEntry.cs | 8 +- .../Imports/DelayedImportHintNameTable.cs | 9 +- .../Content/Imports/DelayedImports.cs | 2 +- .../Imports/ImportDirectoryEntryBase.cs | 168 ++++---- .../Content/Imports/ImportLibraryBase.cs | 180 ++++----- .../Content/Imports/ImportLibraryFunction.cs | 196 +++++----- .../Content/Imports/ImportsBase.cs | 132 +++---- .../Content/Relocation/RelocationTable.cs | 8 + .../Content/Resources/Resource.cs | 364 +++++++++--------- 16 files changed, 675 insertions(+), 557 deletions(-) diff --git a/Src/Workshell.PE/Content/CLR/CLRHeader.cs b/Src/Workshell.PE/Content/CLR/CLRHeader.cs index 2413792..25bcb51 100644 --- a/Src/Workshell.PE/Content/CLR/CLRHeader.cs +++ b/Src/Workshell.PE/Content/CLR/CLRHeader.cs @@ -207,10 +207,10 @@ public CLRDataDirectory GetManagedNativeHeader() [FieldAnnotation("Minor Runtime Version", Order = 3)] public ushort MinorRuntimeVersion { get; } - [FieldAnnotation("MetaData Virtual Address", Order = 4)] + [FieldAnnotation("Meta-data Virtual Address", Order = 4)] public uint MetaDataAddress { get; } - [FieldAnnotation("MetaData Size", Order = 5)] + [FieldAnnotation("Meta-data Size", Order = 5)] public uint MetaDataSize { get; } [FieldAnnotation("Flags", Order = 6)] @@ -225,10 +225,10 @@ public CLRDataDirectory GetManagedNativeHeader() [FieldAnnotation("Resources Size", Order = 9)] public uint ResourcesSize { get; } - [FieldAnnotation("Strongname Signature Virtual Address", Order = 10)] + [FieldAnnotation("Strong-name Signature Virtual Address", Order = 10)] public uint StrongNameSignatureAddress { get; } - [FieldAnnotation("Strongname Signature Size", Order = 11)] + [FieldAnnotation("Strong-name Signature Size", Order = 11)] public uint StrongNameSignatureSize { get; } [FieldAnnotation("Code Manager Table Virtual Address", Order = 12)] diff --git a/Src/Workshell.PE/Location.cs b/Src/Workshell.PE/Location.cs index c733f53..f4abf69 100644 --- a/Src/Workshell.PE/Location.cs +++ b/Src/Workshell.PE/Location.cs @@ -48,7 +48,6 @@ internal Location(PortableExecutableImage image, long fileOffset, uint rva, ulon VirtualSize = virtualSize; } - #region Methods public override string ToString() diff --git a/Src/Workshell.PE/SectionTable.cs b/Src/Workshell.PE/SectionTable.cs index c770d9f..35864b8 100644 --- a/Src/Workshell.PE/SectionTable.cs +++ b/Src/Workshell.PE/SectionTable.cs @@ -232,6 +232,19 @@ public SectionCharacteristicsType GetCharacteristics() return (SectionCharacteristicsType)_header.Characteristics; } + public Section GetSection() + { + foreach(var section in _image.Sections) + { + if (section.TableEntry == this) + { + return section; + } + } + + return null; + } + private string GetName() { var builder = new StringBuilder(16); @@ -257,6 +270,8 @@ private string GetName() public string Name { get; } + public bool IsEmpty => (_header.SizeOfRawData == 0); + public uint VirtualSizeOrPhysicalAddress => _header.VirtualSize; public uint VirtualAddress => _header.VirtualAddress; public uint SizeOfRawData => _header.SizeOfRawData; diff --git a/src/Workshell.PE/Content/Debug/DebugDirectoryEntry.cs b/src/Workshell.PE/Content/Debug/DebugDirectoryEntry.cs index 3426d09..f63fcd7 100644 --- a/src/Workshell.PE/Content/Debug/DebugDirectoryEntry.cs +++ b/src/Workshell.PE/Content/Debug/DebugDirectoryEntry.cs @@ -134,7 +134,6 @@ public DebugData GetData() return null; } - var calc = _image.GetCalculator(); var rva = AddressOfRawData; var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; var location = new Location(_image, PointerToRawData, rva, imageBase + rva, SizeOfData, SizeOfData); diff --git a/src/Workshell.PE/Content/Exports/ExportTable.cs b/src/Workshell.PE/Content/Exports/ExportTable.cs index 89486a4..ce7c730 100644 --- a/src/Workshell.PE/Content/Exports/ExportTable.cs +++ b/src/Workshell.PE/Content/Exports/ExportTable.cs @@ -38,10 +38,27 @@ protected ExportTable(PortableExecutableImage image, DataDirectory dataDirectory #region Static Methods + public static ExportTable GetFunctionAddressTable(PortableExecutableImage image, ExportDirectory directory = null) + { + return GetFunctionAddressTableAsync(image, directory).GetAwaiter().GetResult(); + } + + public static ExportTable GetNameAddressTable(PortableExecutableImage image, ExportDirectory directory = null) + { + return GetNameAddressTableAsync(image, directory).GetAwaiter().GetResult(); + } + + public static ExportTable GetOrdinalTable(PortableExecutableImage image, ExportDirectory directory = null) + { + return GetOrdinalTableAsync(image, directory).GetAwaiter().GetResult(); + } + public static async Task> GetFunctionAddressTableAsync(PortableExecutableImage image, ExportDirectory directory = null) { if (directory == null) + { directory = await ExportDirectory.GetAsync(image).ConfigureAwait(false); + } var calc = image.GetCalculator(); var section = calc.RVAToSection(directory.AddressOfFunctions); @@ -58,7 +75,9 @@ public static async Task> GetFunctionAddressTableAsync(Portabl try { for (var i = 0; i < directory.NumberOfFunctions; i++) + { addresses[i] = await stream.ReadUInt32Async().ConfigureAwait(false); + } } catch (Exception ex) { @@ -75,7 +94,9 @@ public static async Task> GetFunctionAddressTableAsync(Portabl public static async Task> GetNameAddressTableAsync(PortableExecutableImage image, ExportDirectory directory = null) { if (directory == null) + { directory = await ExportDirectory.GetAsync(image).ConfigureAwait(false); + } var calc = image.GetCalculator(); var section = calc.RVAToSection(directory.AddressOfNames); @@ -92,7 +113,9 @@ public static async Task> GetNameAddressTableAsync(PortableExe try { for (var i = 0; i < directory.NumberOfNames; i++) + { addresses[i] = await stream.ReadUInt32Async().ConfigureAwait(false); + } } catch (Exception ex) { @@ -109,7 +132,9 @@ public static async Task> GetNameAddressTableAsync(PortableExe public static async Task> GetOrdinalTableAsync(PortableExecutableImage image, ExportDirectory directory = null) { if (directory == null) + { directory = await ExportDirectory.GetAsync(image).ConfigureAwait(false); + } var calc = image.GetCalculator(); var section = calc.RVAToSection(directory.AddressOfNameOrdinals); @@ -126,7 +151,9 @@ public static async Task> GetOrdinalTableAsync(PortableExecu try { for (var i = 0; i < directory.NumberOfNames; i++) + { ordinals[i] = await stream.ReadUInt16Async().ConfigureAwait(false); + } } catch (Exception ex) { diff --git a/src/Workshell.PE/Content/Imports/DelayedImportAddressTable.cs b/src/Workshell.PE/Content/Imports/DelayedImportAddressTable.cs index 050e6b6..b89ef2f 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportAddressTable.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportAddressTable.cs @@ -1,35 +1,38 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Workshell.PE.Content -{ - public sealed class DelayedImportAddressTable : ImportAddressTableBase - { - internal DelayedImportAddressTable(PortableExecutableImage image, uint rva, ulong[] entries, ImportDirectoryEntryBase directoryEntry) : base(image, rva, entries, directoryEntry, true) - { - } - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Workshell.PE.Extensions; + +namespace Workshell.PE.Content +{ + public sealed class DelayedImportAddressTable : ImportAddressTableBase + { + internal DelayedImportAddressTable(PortableExecutableImage image, uint rva, ulong[] entries, ImportDirectoryEntryBase directoryEntry) : base(image, rva, entries, directoryEntry, true) + { + } + } +} diff --git a/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs b/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs index 93a32cb..0d7efe6 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs @@ -38,17 +38,47 @@ internal DelayedImportAddressTables(PortableExecutableImage image, DataDirectory #region Static Methods - public static async Task GetLookupTableAsync(PortableExecutableImage image, DelayedImportDirectory directory = null) + public static DelayedImportAddressTables GetLookupTables(PortableExecutableImage image, DelayedImportDirectory directory = null) { - return await GetTableAsync(image, directory, (entry) => entry.DelayNameTable).ConfigureAwait(false); + return GetLookupTablesAsync(image, directory).GetAwaiter().GetResult(); } - public static async Task GetAddressTableAsync(PortableExecutableImage image, DelayedImportDirectory directory = null) + public static DelayedImportAddressTables GetAddressTables(PortableExecutableImage image, DelayedImportDirectory directory = null) { - return await GetTableAsync(image, directory, (entry) => entry.DelayAddressTable).ConfigureAwait(false); + return GetAddressTablesAsync(image, directory).GetAwaiter().GetResult(); } - private static async Task GetTableAsync(PortableExecutableImage image, DelayedImportDirectory directory, Func thunkHandler) + public static DelayedImportAddressTables GetBoundAddressTables(PortableExecutableImage image, DelayedImportDirectory directory = null) + { + return GetBoundAddressTablesAsync(image, directory).GetAwaiter().GetResult(); + } + + public static DelayedImportAddressTables GetUnloadAddressTables(PortableExecutableImage image, DelayedImportDirectory directory = null) + { + return GetUnloadAddressTablesAsync(image, directory).GetAwaiter().GetResult(); + } + + public static async Task GetLookupTablesAsync(PortableExecutableImage image, DelayedImportDirectory directory = null) + { + return await GetTablesAsync(image, directory, (entry) => entry.DelayNameTable).ConfigureAwait(false); + } + + public static async Task GetAddressTablesAsync(PortableExecutableImage image, DelayedImportDirectory directory = null) + { + return await GetTablesAsync(image, directory, (entry) => entry.DelayAddressTable).ConfigureAwait(false); + } + + public static async Task GetBoundAddressTablesAsync(PortableExecutableImage image, DelayedImportDirectory directory = null) + { + return await GetTablesAsync(image, directory, (entry) => entry.BoundDelayAddressTable).ConfigureAwait(false); + } + + public static async Task GetUnloadAddressTablesAsync(PortableExecutableImage image, DelayedImportDirectory directory = null) + { + return await GetTablesAsync(image, directory, (entry) => entry.UnloadDelayAddressTable).ConfigureAwait(false); + } + + private static async Task GetTablesAsync(PortableExecutableImage image, DelayedImportDirectory directory, Func thunkHandler) { if (directory == null) directory = await DelayedImportDirectory.GetAsync(image).ConfigureAwait(false); diff --git a/src/Workshell.PE/Content/Imports/DelayedImportDirectoryEntry.cs b/src/Workshell.PE/Content/Imports/DelayedImportDirectoryEntry.cs index 9b13270..7b56ea4 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportDirectoryEntry.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportDirectoryEntry.cs @@ -41,8 +41,8 @@ internal DelayedImportDirectoryEntry(PortableExecutableImage image, Location loc ModuleHandle = descriptor.ModuleHandle; DelayAddressTable = descriptor.DelayAddressTable; DelayNameTable = descriptor.DelayNameTable; - BoundDelayIAT = descriptor.BoundDelayIAT; - UnloadDelayIAT = descriptor.UnloadDelayIAT; + BoundDelayAddressTable = descriptor.BoundDelayIAT; + UnloadDelayAddressTable = descriptor.UnloadDelayIAT; TimeDateStamp = descriptor.TimeDateStamp; } @@ -78,10 +78,10 @@ public string GetName() public uint DelayNameTable { get; } [FieldAnnotation("Bound Delay Import Address Table", Order = 6)] - public uint BoundDelayIAT { get; } + public uint BoundDelayAddressTable { get; } [FieldAnnotation("Unload Delay Import Address Table", Order = 7)] - public uint UnloadDelayIAT { get; } + public uint UnloadDelayAddressTable { get; } [FieldAnnotation("Date/Time Stamp", Order = 8)] public uint TimeDateStamp { get; } diff --git a/src/Workshell.PE/Content/Imports/DelayedImportHintNameTable.cs b/src/Workshell.PE/Content/Imports/DelayedImportHintNameTable.cs index 5a3200e..4886f1c 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportHintNameTable.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportHintNameTable.cs @@ -38,13 +38,20 @@ internal DelayedImportHintNameTable(PortableExecutableImage image, DataDirectory #region Static Methods + public static DelayedImportHintNameTable Get(PortableExecutableImage image, DelayedImportDirectory directory = null) + { + return GetAsync(image, directory).GetAwaiter().GetResult(); + } + public static async Task GetAsync(PortableExecutableImage image, DelayedImportDirectory directory = null) { if (directory == null) + { directory = await DelayedImportDirectory.GetAsync(image).ConfigureAwait(false); + } var entries = new Dictionary>(); - var ilt = await DelayedImportAddressTables.GetLookupTableAsync(image, directory).ConfigureAwait(false); + var ilt = await DelayedImportAddressTables.GetLookupTablesAsync(image, directory).ConfigureAwait(false); var calc = image.GetCalculator(); var stream = image.GetStream(); diff --git a/src/Workshell.PE/Content/Imports/DelayedImports.cs b/src/Workshell.PE/Content/Imports/DelayedImports.cs index dbb41eb..70127b5 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImports.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImports.cs @@ -58,7 +58,7 @@ public static async Task GetAsync(PortableExecutableImage image) return null; } - var ilt = await DelayedImportAddressTables.GetLookupTableAsync(image, directory).ConfigureAwait(false); + var ilt = await DelayedImportAddressTables.GetLookupTablesAsync(image, directory).ConfigureAwait(false); if (ilt == null) { diff --git a/src/Workshell.PE/Content/Imports/ImportDirectoryEntryBase.cs b/src/Workshell.PE/Content/Imports/ImportDirectoryEntryBase.cs index 5a8e36b..63cc5ca 100644 --- a/src/Workshell.PE/Content/Imports/ImportDirectoryEntryBase.cs +++ b/src/Workshell.PE/Content/Imports/ImportDirectoryEntryBase.cs @@ -1,69 +1,99 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Workshell.PE.Extensions; - -namespace Workshell.PE.Content -{ - - public abstract class ImportDirectoryEntryBase : ISupportsLocation, ISupportsBytes - { - private readonly PortableExecutableImage _image; - - protected internal ImportDirectoryEntryBase(PortableExecutableImage image, Location location, bool isDelayed) - { - _image = image; - - Location = location; - IsDelayed = isDelayed; - } - - #region Methods - - public byte[] GetBytes() - { - return GetBytesAsync().GetAwaiter().GetResult(); - } - - public async Task GetBytesAsync() - { - var stream = _image.GetStream(); - var buffer = await stream.ReadBytesAsync(Location).ConfigureAwait(false); - - return buffer; - } - - #endregion - - #region Properties - - public Location Location { get; } - public bool IsDelayed { get; } - public abstract uint Name { get; } - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Workshell.PE.Extensions; + +namespace Workshell.PE.Content +{ + + public abstract class ImportDirectoryEntryBase : ISupportsLocation, ISupportsBytes + { + private readonly PortableExecutableImage _image; + + protected internal ImportDirectoryEntryBase(PortableExecutableImage image, Location location, bool isDelayed) + { + _image = image; + + Location = location; + IsDelayed = isDelayed; + } + + #region Methods + + public byte[] GetBytes() + { + return GetBytesAsync().GetAwaiter().GetResult(); + } + + public async Task GetBytesAsync() + { + var stream = _image.GetStream(); + var buffer = await stream.ReadBytesAsync(Location).ConfigureAwait(false); + + return buffer; + } + + public string GetName() + { + return GetNameAsync().GetAwaiter().GetResult(); + } + + public async Task GetNameAsync() + { + var stream = _image.GetStream(); + var calc = _image.GetCalculator(); + var builder = new StringBuilder(256); + var offset = calc.RVAToOffset(Name); + + stream.Seek(offset, SeekOrigin.Begin); + + while (true) + { + var b = await stream.ReadByteAsync().ConfigureAwait(false); + + if (b <= 0) + { + break; + } + + builder.Append((char)b); + } + + return builder.ToString(); + } + + #endregion + + #region Properties + + public Location Location { get; } + public bool IsDelayed { get; } + public abstract uint Name { get; } + + #endregion + } +} diff --git a/src/Workshell.PE/Content/Imports/ImportLibraryBase.cs b/src/Workshell.PE/Content/Imports/ImportLibraryBase.cs index aeb43a7..ee86127 100644 --- a/src/Workshell.PE/Content/Imports/ImportLibraryBase.cs +++ b/src/Workshell.PE/Content/Imports/ImportLibraryBase.cs @@ -1,90 +1,90 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Workshell.PE.Content -{ - public abstract class ImportLibraryBase : IEnumerable - { - private readonly ImportLibraryFunction[] _functions; - - protected internal ImportLibraryBase(ImportLibraryFunction[] functions, string name, bool isDelayed) - { - _functions = functions; - - Name = name; - Count = _functions.Length; - IsDelayed = isDelayed; - } - - #region Methods - - public IEnumerator GetEnumerator() - { - foreach (var function in _functions) - yield return function; - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public override string ToString() - { - return $"Name: {Name}, Imported Function Count: {_functions.Length}"; - } - - public IEnumerable GetNamedFunctions() - { - foreach (var function in _functions) - { - if (function.BindingType == ImportLibraryBindingType.Name) - yield return (ImportLibraryNamedFunction)function; - } - } - - public IEnumerable GetOrdinalFunctions() - { - foreach (var function in _functions) - { - if (function.BindingType == ImportLibraryBindingType.Ordinal) - yield return (ImportLibraryOrdinalFunction)function; - } - } - - #endregion - - #region Properties - - public ImportLibraryFunction this[int index] => _functions[index]; - public string Name { get; } - public int Count { get; } - public bool IsDelayed { get; } - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Workshell.PE.Content +{ + public abstract class ImportLibraryBase : IEnumerable + { + private readonly ImportLibraryFunction[] _functions; + + protected internal ImportLibraryBase(ImportLibraryFunction[] functions, string name, bool isDelayed) + { + _functions = functions; + + Name = name; + Count = _functions.Length; + IsDelayed = isDelayed; + } + + #region Methods + + public IEnumerator GetEnumerator() + { + foreach (var function in _functions) + yield return function; + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public override string ToString() + { + return $"Name: {Name}, Imported Function Count: {_functions.Length}"; + } + + public IEnumerable GetNamedFunctions() + { + foreach (var function in _functions) + { + if (function.BindingType == ImportLibraryBindingType.Name) + yield return (ImportLibraryNamedFunction)function; + } + } + + public IEnumerable GetOrdinalFunctions() + { + foreach (var function in _functions) + { + if (function.BindingType == ImportLibraryBindingType.Ordinal) + yield return (ImportLibraryOrdinalFunction)function; + } + } + + #endregion + + #region Properties + + public ImportLibraryFunction this[int index] => _functions[index]; + public string Name { get; } + public int Count { get; } + public bool IsDelayed { get; } + + #endregion + } +} diff --git a/src/Workshell.PE/Content/Imports/ImportLibraryFunction.cs b/src/Workshell.PE/Content/Imports/ImportLibraryFunction.cs index 6b6bee6..081f870 100644 --- a/src/Workshell.PE/Content/Imports/ImportLibraryFunction.cs +++ b/src/Workshell.PE/Content/Imports/ImportLibraryFunction.cs @@ -1,98 +1,98 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Workshell.PE.Content -{ - public enum ImportLibraryBindingType - { - Name, - Ordinal - } - - public abstract class ImportLibraryFunction - { - internal ImportLibraryFunction(ImportAddressTableEntryBase tableEntry) - { - TableEntry = tableEntry; - } - - #region Properties - - public ImportAddressTableEntryBase TableEntry { get; } - public abstract ImportLibraryBindingType BindingType { get; } - - #endregion - } - - public sealed class ImportLibraryOrdinalFunction : ImportLibraryFunction - { - internal ImportLibraryOrdinalFunction(ImportAddressTableEntryBase tableEntry, int ordinal) : base(tableEntry) - { - Ordinal = ordinal; - } - - #region Methods - - public override string ToString() - { - return $"{Ordinal:D4} (0x{Ordinal:X4})"; - } - - #endregion - - #region Properties - - public override ImportLibraryBindingType BindingType => ImportLibraryBindingType.Ordinal; - public int Ordinal { get; } - - #endregion - } - - public sealed class ImportLibraryNamedFunction : ImportLibraryFunction - { - internal ImportLibraryNamedFunction(ImportAddressTableEntryBase tableEntry, ImportHintNameEntryBase hintEntry) : base(tableEntry) - { - HintEntry = hintEntry; - } - - #region Methods - - public override string ToString() - { - return HintEntry.ToString(); - } - - #endregion - - #region Properties - - public override ImportLibraryBindingType BindingType => ImportLibraryBindingType.Name; - public ImportHintNameEntryBase HintEntry { get; } - public string Name => HintEntry.Name; - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Workshell.PE.Content +{ + public enum ImportLibraryBindingType + { + Name, + Ordinal + } + + public abstract class ImportLibraryFunction + { + internal ImportLibraryFunction(ImportAddressTableEntryBase tableEntry) + { + TableEntry = tableEntry; + } + + #region Properties + + public ImportAddressTableEntryBase TableEntry { get; } + public abstract ImportLibraryBindingType BindingType { get; } + + #endregion + } + + public sealed class ImportLibraryOrdinalFunction : ImportLibraryFunction + { + internal ImportLibraryOrdinalFunction(ImportAddressTableEntryBase tableEntry, int ordinal) : base(tableEntry) + { + Ordinal = ordinal; + } + + #region Methods + + public override string ToString() + { + return $"{Ordinal:D4} (0x{Ordinal:X4})"; + } + + #endregion + + #region Properties + + public override ImportLibraryBindingType BindingType => ImportLibraryBindingType.Ordinal; + public int Ordinal { get; } + + #endregion + } + + public sealed class ImportLibraryNamedFunction : ImportLibraryFunction + { + internal ImportLibraryNamedFunction(ImportAddressTableEntryBase tableEntry, ImportHintNameEntryBase hintEntry) : base(tableEntry) + { + HintEntry = hintEntry; + } + + #region Methods + + public override string ToString() + { + return HintEntry.ToString(); + } + + #endregion + + #region Properties + + public override ImportLibraryBindingType BindingType => ImportLibraryBindingType.Name; + public ImportHintNameEntryBase HintEntry { get; } + public string Name => HintEntry.Name; + + #endregion + } +} diff --git a/src/Workshell.PE/Content/Imports/ImportsBase.cs b/src/Workshell.PE/Content/Imports/ImportsBase.cs index da7ef14..e4afc67 100644 --- a/src/Workshell.PE/Content/Imports/ImportsBase.cs +++ b/src/Workshell.PE/Content/Imports/ImportsBase.cs @@ -1,66 +1,66 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Workshell.PE.Content -{ - public abstract class ImportsBase : IEnumerable - where TLibrary : ImportLibraryBase - { - private readonly TLibrary[] _libraries; - - protected internal ImportsBase(TLibrary[] libraries) - { - _libraries = libraries; - - Count = _libraries.Length; - } - - #region Methods - - public IEnumerator GetEnumerator() - { - foreach (var library in _libraries) - yield return library; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - #endregion - - #region Properties - - public int Count { get; } - public TLibrary this[int index] => _libraries[index]; - public TLibrary this[string name] => _libraries.FirstOrDefault(lib => string.Compare(name, lib.Name, StringComparison.OrdinalIgnoreCase) == 0); - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Workshell.PE.Content +{ + public abstract class ImportsBase : IEnumerable + where TLibrary : ImportLibraryBase + { + private readonly TLibrary[] _libraries; + + protected internal ImportsBase(TLibrary[] libraries) + { + _libraries = libraries; + + Count = _libraries.Length; + } + + #region Methods + + public IEnumerator GetEnumerator() + { + foreach (var library in _libraries) + yield return library; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + #region Properties + + public int Count { get; } + public TLibrary this[int index] => _libraries[index]; + public TLibrary this[string name] => _libraries.FirstOrDefault(lib => string.Compare(name, lib.Name, StringComparison.OrdinalIgnoreCase) == 0); + + #endregion + } +} diff --git a/src/Workshell.PE/Content/Relocation/RelocationTable.cs b/src/Workshell.PE/Content/Relocation/RelocationTable.cs index 620e731..b2a574b 100644 --- a/src/Workshell.PE/Content/Relocation/RelocationTable.cs +++ b/src/Workshell.PE/Content/Relocation/RelocationTable.cs @@ -52,12 +52,16 @@ public static RelocationTable Get(PortableExecutableImage image) public static async Task GetAsync(PortableExecutableImage image) { if (!image.NTHeaders.DataDirectories.Exists(DataDirectoryType.BaseRelocationTable)) + { return null; + } var dataDirectory = image.NTHeaders.DataDirectories[DataDirectoryType.BaseRelocationTable]; if (DataDirectory.IsNullOrEmpty(dataDirectory)) + { return null; + } var calc = image.GetCalculator(); var section = calc.RVAToSection(dataDirectory.VirtualAddress); @@ -109,7 +113,9 @@ public static async Task GetAsync(PortableExecutableImage image blocks.Add(block); if (blockSize >= dataDirectory.Size) + { break; + } blockOffset += sizeof(ulong); blockOffset += sizeof(ushort) * count; @@ -125,7 +131,9 @@ public static async Task GetAsync(PortableExecutableImage image public IEnumerator GetEnumerator() { foreach (var block in _blocks) + { yield return block; + } } IEnumerator IEnumerable.GetEnumerator() diff --git a/src/Workshell.PE/Content/Resources/Resource.cs b/src/Workshell.PE/Content/Resources/Resource.cs index 6c9044a..d5275cf 100644 --- a/src/Workshell.PE/Content/Resources/Resource.cs +++ b/src/Workshell.PE/Content/Resources/Resource.cs @@ -1,182 +1,182 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Workshell.PE.Resources -{ - public class Resource : ISupportsBytes - { - private readonly Dictionary _languages; - - protected Resource(PortableExecutableImage image, ResourceType type, ResourceDirectoryEntry entry, ResourceId id) - { - _languages = BuildLanguages(entry); - - Type = type; - Entry = entry; - Id = id; - Languages = _languages.Keys.OrderBy(k => k).ToArray(); - Image = image; - } - - #region Static Methods - - internal static async Task CreateAsync(PortableExecutableImage image, ResourceType type, ResourceDirectoryEntry entry, Type resourceType) - { - ResourceId id; - - if (entry.NameType == NameType.ID) - { - id = entry.GetId(); - } - else - { - id = await entry.GetNameAsync().ConfigureAwait(false); - } - - var ctors = resourceType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - var ctor = ctors.First(); - var resource = (Resource)ctor.Invoke(new object[] { image, type, entry, id }); - - return resource; - } - - #endregion - - #region Methods - - public override string ToString() - { - if (!Id.IsNumeric) - return Id.Name; - - return $"#{Id}"; - } - - public ResourceData GetData() - { - return GetData(ResourceLanguage.English.UnitedStates); - } - - public async Task GetDataAsync() - { - return await GetDataAsync(ResourceLanguage.English.UnitedStates).ConfigureAwait(false); - } - - public ResourceData GetData(ResourceLanguage language) - { - return GetDataAsync(language).GetAwaiter().GetResult(); - } - - public async Task GetDataAsync(ResourceLanguage language) - { - if (!_languages.ContainsKey(language)) - return null; - - var languageEntry = _languages[language]; - var entry = await languageEntry.GetDataEntryAsync().ConfigureAwait(false); - var data = entry.GetData(); - - return data; - } - - public byte[] GetBytes() - { - return GetBytes(ResourceLanguage.English.UnitedStates); - } - - public async Task GetBytesAsync() - { - return await GetBytesAsync(ResourceLanguage.English.UnitedStates); - } - - public byte[] GetBytes(ResourceLanguage language) - { - return GetBytesAsync(language).GetAwaiter().GetResult(); - } - - public async Task GetBytesAsync(ResourceLanguage language) - { - if (!_languages.ContainsKey(language)) - throw new PortableExecutableImageException(Image, $"Cannot find specified language: {language}"); - - var data = await GetDataAsync(language).ConfigureAwait(false); - - if (data == null) - throw new PortableExecutableImageException(Image, $"Cannot find resource data for language: {language}"); - - return await data.GetBytesAsync().ConfigureAwait(false); - } - - public void CopyTo(Stream stream) - { - CopyTo(stream, ResourceLanguage.English.UnitedStates); - } - - public async Task CopyToAsync(Stream stream) - { - await CopyToAsync(stream, ResourceLanguage.English.UnitedStates).ConfigureAwait(false); - } - - public void CopyTo(Stream stream, ResourceLanguage language) - { - CopyToAsync(stream, language).GetAwaiter().GetResult(); - } - - public async Task CopyToAsync(Stream stream, ResourceLanguage language) - { - var data = await GetDataAsync(language).ConfigureAwait(false); - - await data.CopyToAsync(stream).ConfigureAwait(false); - } - - private Dictionary BuildLanguages(ResourceDirectoryEntry parentEntry) - { - var results = new Dictionary(); - var directory = parentEntry.GetDirectory(); - - foreach (var entry in directory) - results.Add(entry.GetId(),entry); - - return results; - } - - #endregion - - #region Properties - - public ResourceType Type { get; } - public ResourceDirectoryEntry Entry { get; } - public ResourceId Id { get; } - public ResourceLanguage[] Languages { get; } - protected PortableExecutableImage Image { get; } - - #endregion - } -} +#region License +// Copyright(c) Workshell Ltd +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Workshell.PE.Resources +{ + public class Resource : ISupportsBytes + { + private readonly Dictionary _languages; + + protected Resource(PortableExecutableImage image, ResourceType type, ResourceDirectoryEntry entry, ResourceId id) + { + _languages = BuildLanguages(entry); + + Type = type; + Entry = entry; + Id = id; + Languages = _languages.Keys.OrderBy(res => res.LCID).ToArray(); + Image = image; + } + + #region Static Methods + + internal static async Task CreateAsync(PortableExecutableImage image, ResourceType type, ResourceDirectoryEntry entry, Type resourceType) + { + ResourceId id; + + if (entry.NameType == NameType.ID) + { + id = entry.GetId(); + } + else + { + id = await entry.GetNameAsync().ConfigureAwait(false); + } + + var ctors = resourceType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + var ctor = ctors.First(); + var resource = (Resource)ctor.Invoke(new object[] { image, type, entry, id }); + + return resource; + } + + #endregion + + #region Methods + + public override string ToString() + { + if (!Id.IsNumeric) + return Id.Name; + + return $"#{Id}"; + } + + public ResourceData GetData() + { + return GetData(ResourceLanguage.English.UnitedStates); + } + + public async Task GetDataAsync() + { + return await GetDataAsync(ResourceLanguage.English.UnitedStates).ConfigureAwait(false); + } + + public ResourceData GetData(ResourceLanguage language) + { + return GetDataAsync(language).GetAwaiter().GetResult(); + } + + public async Task GetDataAsync(ResourceLanguage language) + { + if (!_languages.ContainsKey(language)) + return null; + + var languageEntry = _languages[language]; + var entry = await languageEntry.GetDataEntryAsync().ConfigureAwait(false); + var data = entry.GetData(); + + return data; + } + + public byte[] GetBytes() + { + return GetBytes(ResourceLanguage.English.UnitedStates); + } + + public async Task GetBytesAsync() + { + return await GetBytesAsync(ResourceLanguage.English.UnitedStates); + } + + public byte[] GetBytes(ResourceLanguage language) + { + return GetBytesAsync(language).GetAwaiter().GetResult(); + } + + public async Task GetBytesAsync(ResourceLanguage language) + { + if (!_languages.ContainsKey(language)) + throw new PortableExecutableImageException(Image, $"Cannot find specified language: {language}"); + + var data = await GetDataAsync(language).ConfigureAwait(false); + + if (data == null) + throw new PortableExecutableImageException(Image, $"Cannot find resource data for language: {language}"); + + return await data.GetBytesAsync().ConfigureAwait(false); + } + + public void CopyTo(Stream stream) + { + CopyTo(stream, ResourceLanguage.English.UnitedStates); + } + + public async Task CopyToAsync(Stream stream) + { + await CopyToAsync(stream, ResourceLanguage.English.UnitedStates).ConfigureAwait(false); + } + + public void CopyTo(Stream stream, ResourceLanguage language) + { + CopyToAsync(stream, language).GetAwaiter().GetResult(); + } + + public async Task CopyToAsync(Stream stream, ResourceLanguage language) + { + var data = await GetDataAsync(language).ConfigureAwait(false); + + await data.CopyToAsync(stream).ConfigureAwait(false); + } + + private Dictionary BuildLanguages(ResourceDirectoryEntry parentEntry) + { + var results = new Dictionary(); + var directory = parentEntry.GetDirectory(); + + foreach (var entry in directory) + results.Add(entry.GetId(),entry); + + return results; + } + + #endregion + + #region Properties + + public ResourceType Type { get; } + public ResourceDirectoryEntry Entry { get; } + public ResourceId Id { get; } + public ResourceLanguage[] Languages { get; } + protected PortableExecutableImage Image { get; } + + #endregion + } +} From 3e25514be490846e4269f4ebe229a99a9bcf19dd Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Fri, 8 Nov 2019 17:40:34 +0000 Subject: [PATCH 04/12] Location calc tests and fixed integer type issue. --- Src/Workshell.PE/LocationCalculator.cs | 55 ++++---- tests/Workshell.PE.Tests/DOSHeaderTests.cs | 12 +- .../LocationCalculatorTests.cs | 123 ++++++++++++++++++ 3 files changed, 152 insertions(+), 38 deletions(-) diff --git a/Src/Workshell.PE/LocationCalculator.cs b/Src/Workshell.PE/LocationCalculator.cs index 11b2494..c5bc4bd 100644 --- a/Src/Workshell.PE/LocationCalculator.cs +++ b/Src/Workshell.PE/LocationCalculator.cs @@ -31,7 +31,7 @@ namespace Workshell.PE { public sealed class LocationCalculator { - private PortableExecutableImage _image; + private readonly PortableExecutableImage _image; internal LocationCalculator(PortableExecutableImage image) { @@ -52,18 +52,32 @@ public Location OffsetToLocation(long offset, long size) public Section VAToSection(ulong va) { - var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; - var rva = (va - imageBase).ToUInt32(); + try + { + var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; + var rva = (va - imageBase).ToUInt32(); - return RVAToSection(rva); + return RVAToSection(rva); + } + catch (OverflowException) + { + return null; + } } public SectionTableEntry VAToSectionTableEntry(ulong va) { - var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; - var rva = (va - imageBase).ToUInt32(); + try + { + var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; + var rva = (va - imageBase).ToUInt32(); - return RVAToSectionTableEntry(rva); + return RVAToSectionTableEntry(rva); + } + catch (OverflowException) + { + return null; + } } public long VAToOffset(ulong va) @@ -74,19 +88,6 @@ public long VAToOffset(ulong va) return RVAToOffset(rva); } - public long VAToOffset(Section section, ulong va) - { - return VAToOffset(section.TableEntry, va); - } - - public long VAToOffset(SectionTableEntry section, ulong va) - { - var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; - var rva = (va - imageBase).ToUInt32(); - - return RVAToOffset(section, rva); - } - public ulong OffsetToVA(long offset) { var entries = _image.SectionTable.OrderBy(e => e.PointerToRawData) @@ -109,12 +110,7 @@ public ulong OffsetToVA(long offset) return 0; } - public ulong OffsetToVA(Section section, long offset) - { - return OffsetToVA(section.TableEntry, offset); - } - - public ulong OffsetToVA(SectionTableEntry section, long offset) + private ulong OffsetToVA(SectionTableEntry section, long offset) { var imageBase = _image.NTHeaders.OptionalHeader.ImageBase; var rva = ((offset + section.VirtualAddress) - section.PointerToRawData).ToUInt32(); @@ -220,12 +216,7 @@ public uint OffsetToRVA(long offset) return 0; } - public uint OffsetToRVA(Section section, long offset) - { - return OffsetToRVA(section.TableEntry, offset); - } - - public uint OffsetToRVA(SectionTableEntry section, long offset) + private uint OffsetToRVA(SectionTableEntry section, long offset) { var rva = ((offset + section.VirtualAddress) - section.PointerToRawData).ToUInt32(); diff --git a/tests/Workshell.PE.Tests/DOSHeaderTests.cs b/tests/Workshell.PE.Tests/DOSHeaderTests.cs index 643f57d..24c19e7 100644 --- a/tests/Workshell.PE.Tests/DOSHeaderTests.cs +++ b/tests/Workshell.PE.Tests/DOSHeaderTests.cs @@ -55,12 +55,12 @@ public void File_Address_Relocation_Table_Is_Correct(string fileName, int expect } } - [TestCase("clrtest.any.dll", 0x00000080)] - [TestCase("clrtest.x86.dll", 0x00000080)] - [TestCase("clrtest.x64.dll", 0x00000080)] - [TestCase("nativetest.x86.dll", 0x00000100)] - [TestCase("nativetest.x64.dll", 0x00000100)] - public void File_Address_New_Header_Is_Correct(string fileName, int expectedValue) + [TestCase("clrtest.any.dll", 0x00000080U)] + [TestCase("clrtest.x86.dll", 0x00000080U)] + [TestCase("clrtest.x64.dll", 0x00000080U)] + [TestCase("nativetest.x86.dll", 0x00000100U)] + [TestCase("nativetest.x64.dll", 0x00000100U)] + public void File_Address_New_Header_Is_Correct(string fileName, uint expectedValue) { var file = TestingUtils.GetFileFromResources(fileName); diff --git a/tests/Workshell.PE.Tests/LocationCalculatorTests.cs b/tests/Workshell.PE.Tests/LocationCalculatorTests.cs index 75242f5..bb1bea7 100644 --- a/tests/Workshell.PE.Tests/LocationCalculatorTests.cs +++ b/tests/Workshell.PE.Tests/LocationCalculatorTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; +using FluentAssertions; using NUnit.Framework; namespace Workshell.PE.Tests @@ -25,5 +26,127 @@ public void TearDown() _calc = null; _image.Dispose(); } + + [Test] + public void OffsetToLocation_Returns_Location() + { + var output = _calc.OffsetToLocation(0x000000000000F250, 14); + + output.Should().NotBeNull(); + } + + [Test] + public void OffsetToLocation_Returns_Correct_Location() + { + var output = _calc.OffsetToLocation(0x000000000000F250, 14); + + output.FileOffset.Should().Be(0x000000000000F250); + output.FileSize.Should().Be(14); + output.VirtualAddress.Should().Be(0x0000000000419050); + output.VirtualSize.Should().Be(14); + output.RelativeVirtualAddress.Should().Be(0x00019050); + output.Section.Should().NotBeNull(); + output.Section.Name.Should().Be(".edata"); + } + + [Test] + public void VAToSection_Outside_Of_Section_Returns_Null() + { + var output = _calc.VAToSection(0x00000050); + + output.Should().BeNull(); + } + + [Test] + public void VAToSection_Returns_Correct_Section() + { + var output = _calc.VAToSection(0x0000000000419050); + + output.Should().NotBeNull(); + output.Name.Should().Be(".edata"); + } + + [Test] + public void VAToSectionTableEntry_Outside_Of_Section_Returns_Null() + { + var output = _calc.VAToSectionTableEntry(0x00000050); + + output.Should().BeNull(); + } + + [Test] + public void VAToSectionTableEntry_Returns_Correct_Section() + { + var output = _calc.VAToSectionTableEntry(0x0000000000419050); + + output.Should().NotBeNull(); + output.Name.Should().Be(".edata"); + } + + [Test] + public void VAToOffset_Returns_Correct_Value() + { + var output = _calc.VAToOffset(0x0000000000419050); + + output.Should().Be(0x000000000000F250); + } + + [Test] + public void OffsetToVA_Returns_Correct_Value() + { + var output = _calc.OffsetToVA(0x000000000000F250); + + output.Should().Be(0x0000000000419050); + } + + [Test] + public void RVAToSection_Outside_Of_Section_Returns_Null() + { + var output = _calc.RVAToSection(0x00000050); + + output.Should().BeNull(); + } + + [Test] + public void RVAToSection_Returns_Correct_Section() + { + var output = _calc.RVAToSection(0x00019050); + + output.Should().NotBeNull(); + output.Name.Should().Be(".edata"); + } + + [Test] + public void RVAToSectionTableEntry_Outside_Of_Section_Returns_Null() + { + var output = _calc.RVAToSectionTableEntry(0x00000050); + + output.Should().BeNull(); + } + + [Test] + public void RVAToSectionTableEntry_Returns_Correct_Section() + { + var output = _calc.RVAToSectionTableEntry(0x00019050); + + output.Should().NotBeNull(); + output.Name.Should().Be(".edata"); + } + + [Test] + public void RVAToOffset_Returns_Correct_Value() + { + var output = _calc.RVAToOffset(0x00019050); + + output.Should().Be(0x000000000000F250); + } + + [Test] + public void OffsetToRVA_Returns_Correct_Value() + { + var output = _calc.OffsetToRVA(0x000000000000F250); + + output.Should().Be(0x00019050); + } } } From 21e7150de24b82fc298150f08b702310a412d118 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Sat, 9 Nov 2019 00:41:30 +0000 Subject: [PATCH 05/12] Removed license.txt from Solution Items. --- dotNET PE.sln | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dotNET PE.sln b/dotNET PE.sln index 9aff616..7ae86ce 100644 --- a/dotNET PE.sln +++ b/dotNET PE.sln @@ -11,9 +11,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject src\CommonAssemblyInfo.cs = src\CommonAssemblyInfo.cs readme.md = readme.md + version.txt = version.txt EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workshell.PE.Tests", "tests\Workshell.PE.Tests\Workshell.PE.Tests.csproj", "{8A5FC684-11D6-4902-B0E0-7FEBC36BA21F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Workshell.PE.Tests", "tests\Workshell.PE.Tests\Workshell.PE.Tests.csproj", "{8A5FC684-11D6-4902-B0E0-7FEBC36BA21F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From c5c66bf8d8131aa930b3484d30f0d630ef24ef03 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Sun, 17 Nov 2019 00:33:38 +0000 Subject: [PATCH 06/12] More changes from PEI land. --- .../Content/Debug/DebugDirectoryEntry.cs | 2 ++ .../Content/Imports/ImportAddressTables.cs | 20 ++++++++++++++----- .../Content/Imports/ImportHintNameTable.cs | 7 ++++++- src/Workshell.PE/Content/Imports/Imports.cs | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Workshell.PE/Content/Debug/DebugDirectoryEntry.cs b/src/Workshell.PE/Content/Debug/DebugDirectoryEntry.cs index f63fcd7..8a04b92 100644 --- a/src/Workshell.PE/Content/Debug/DebugDirectoryEntry.cs +++ b/src/Workshell.PE/Content/Debug/DebugDirectoryEntry.cs @@ -174,6 +174,8 @@ public DebugData GetData() [FieldAnnotation("Pointer to Raw Data", Order = 8)] public uint PointerToRawData { get; } + public bool IsEmpty => (PointerToRawData == 0 && SizeOfData == 0); + #endregion } } diff --git a/src/Workshell.PE/Content/Imports/ImportAddressTables.cs b/src/Workshell.PE/Content/Imports/ImportAddressTables.cs index b77c1eb..d860f64 100644 --- a/src/Workshell.PE/Content/Imports/ImportAddressTables.cs +++ b/src/Workshell.PE/Content/Imports/ImportAddressTables.cs @@ -38,17 +38,27 @@ internal ImportAddressTables(PortableExecutableImage image, DataDirectory dataDi #region Static Methods - public static async Task GetLookupTableAsync(PortableExecutableImage image, ImportDirectory directory = null) + public static ImportAddressTables GetLookupTables(PortableExecutableImage image, ImportDirectory directory = null) { - return await GetTableAsync(image, directory, (entry) => entry.OriginalFirstThunk).ConfigureAwait(false); + return GetLookupTablesAsync(image, directory).GetAwaiter().GetResult(); } - public static async Task GetAddressTableAsync(PortableExecutableImage image, ImportDirectory directory = null) + public static ImportAddressTables GetAddressTables(PortableExecutableImage image, ImportDirectory directory = null) { - return await GetTableAsync(image, directory, (entry) => entry.FirstThunk).ConfigureAwait(false); + return GetAddressTablesAsync(image, directory).GetAwaiter().GetResult(); } - private static async Task GetTableAsync(PortableExecutableImage image, ImportDirectory directory, Func thunkHandler) + public static async Task GetLookupTablesAsync(PortableExecutableImage image, ImportDirectory directory = null) + { + return await GetTablesAsync(image, directory, (entry) => entry.OriginalFirstThunk).ConfigureAwait(false); + } + + public static async Task GetAddressTablesAsync(PortableExecutableImage image, ImportDirectory directory = null) + { + return await GetTablesAsync(image, directory, (entry) => entry.FirstThunk).ConfigureAwait(false); + } + + private static async Task GetTablesAsync(PortableExecutableImage image, ImportDirectory directory, Func thunkHandler) { if (directory == null) directory = await ImportDirectory.GetAsync(image).ConfigureAwait(false); diff --git a/src/Workshell.PE/Content/Imports/ImportHintNameTable.cs b/src/Workshell.PE/Content/Imports/ImportHintNameTable.cs index b6c3505..a7f5da8 100644 --- a/src/Workshell.PE/Content/Imports/ImportHintNameTable.cs +++ b/src/Workshell.PE/Content/Imports/ImportHintNameTable.cs @@ -38,6 +38,11 @@ internal ImportHintNameTable(PortableExecutableImage image, DataDirectory dataDi #region Static Methods + public static ImportHintNameTable Get(PortableExecutableImage image, ImportDirectory directory = null) + { + return GetAsync(image, directory).GetAwaiter().GetResult(); + } + public static async Task GetAsync(PortableExecutableImage image, ImportDirectory directory = null) { if (directory == null) @@ -46,7 +51,7 @@ public static async Task GetAsync(PortableExecutableImage i } var entries = new Dictionary>(); - var ilt = await ImportAddressTables.GetLookupTableAsync(image, directory).ConfigureAwait(false); + var ilt = await ImportAddressTables.GetLookupTablesAsync(image, directory).ConfigureAwait(false); var calc = image.GetCalculator(); var stream = image.GetStream(); diff --git a/src/Workshell.PE/Content/Imports/Imports.cs b/src/Workshell.PE/Content/Imports/Imports.cs index fbe9232..1a2581e 100644 --- a/src/Workshell.PE/Content/Imports/Imports.cs +++ b/src/Workshell.PE/Content/Imports/Imports.cs @@ -58,7 +58,7 @@ public static async Task GetAsync(PortableExecutableImage image) return null; } - var ilt = await ImportAddressTables.GetLookupTableAsync(image, directory).ConfigureAwait(false); + var ilt = await ImportAddressTables.GetLookupTablesAsync(image, directory).ConfigureAwait(false); if (ilt == null) { From 56bbfe3eb25ad894c46781d56b5291efcd6ced72 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Fri, 24 Jan 2020 13:46:12 +0000 Subject: [PATCH 07/12] Various tweaks. --- src/Workshell.PE/Content/Exceptions/ExceptionTable.cs | 9 +++++++++ .../Content/Imports/DelayedImportDirectoryEntry.cs | 11 +++++++++++ .../Content/Resources/ResourceDirectory.cs | 4 ++-- .../Content/Resources/ResourceDirectoryEntry.cs | 6 ++++-- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Workshell.PE/Content/Exceptions/ExceptionTable.cs b/src/Workshell.PE/Content/Exceptions/ExceptionTable.cs index 9953b97..cf268d4 100644 --- a/src/Workshell.PE/Content/Exceptions/ExceptionTable.cs +++ b/src/Workshell.PE/Content/Exceptions/ExceptionTable.cs @@ -41,15 +41,24 @@ protected internal ExceptionTable(PortableExecutableImage image, DataDirectory d #region Static Methods + public static ExceptionTable Get(PortableExecutableImage image) + { + return GetAsync(image).GetAwaiter().GetResult(); + } + public static async Task GetAsync(PortableExecutableImage image) { if (!image.NTHeaders.DataDirectories.Exists(DataDirectoryType.ExceptionTable)) + { return null; + } var dataDirectory = image.NTHeaders.DataDirectories[DataDirectoryType.ExceptionTable]; if (DataDirectory.IsNullOrEmpty(dataDirectory)) + { return null; + } var calc = image.GetCalculator(); var section = calc.RVAToSection(dataDirectory.VirtualAddress); diff --git a/src/Workshell.PE/Content/Imports/DelayedImportDirectoryEntry.cs b/src/Workshell.PE/Content/Imports/DelayedImportDirectoryEntry.cs index 7b56ea4..55b04ad 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportDirectoryEntry.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportDirectoryEntry.cs @@ -32,6 +32,11 @@ public sealed class DelayedImportDirectoryEntry : ImportDirectoryEntryBase { private readonly string _name; + static DelayedImportDirectoryEntry() + { + Size = Utils.SizeOf(); + } + internal DelayedImportDirectoryEntry(PortableExecutableImage image, Location location, IMAGE_DELAY_IMPORT_DESCRIPTOR descriptor, string name) : base(image, location, true) { _name = name; @@ -60,6 +65,12 @@ public string GetName() #endregion + #region Static Properties + + public static int Size { get; } + + #endregion + #region Properties [FieldAnnotation("Attributes", Order = 1)] diff --git a/src/Workshell.PE/Content/Resources/ResourceDirectory.cs b/src/Workshell.PE/Content/Resources/ResourceDirectory.cs index c78095c..0976b32 100644 --- a/src/Workshell.PE/Content/Resources/ResourceDirectory.cs +++ b/src/Workshell.PE/Content/Resources/ResourceDirectory.cs @@ -38,10 +38,12 @@ namespace Workshell.PE.Resources public sealed class ResourceDirectory : DataContent, IEnumerable { private ResourceDirectoryEntry[] _entries; + private ResourceDirectory _root; internal ResourceDirectory(PortableExecutableImage image, DataDirectory dataDirectory, Location location, ResourceDirectoryEntry directoryEntry) : base(image, dataDirectory, location) { _entries = new ResourceDirectoryEntry[0]; + _root = null; DirectoryEntry = directoryEntry; } @@ -179,8 +181,6 @@ internal async Task LoadAsync() [FieldAnnotation("Number of ID Entries", Order = 6)] public ushort NumberOfIdEntries { get; private set; } - - #endregion } } diff --git a/src/Workshell.PE/Content/Resources/ResourceDirectoryEntry.cs b/src/Workshell.PE/Content/Resources/ResourceDirectoryEntry.cs index 7e080a9..a4847da 100644 --- a/src/Workshell.PE/Content/Resources/ResourceDirectoryEntry.cs +++ b/src/Workshell.PE/Content/Resources/ResourceDirectoryEntry.cs @@ -71,8 +71,10 @@ internal ResourceDirectoryEntry(PortableExecutableImage image, DataDirectory dat public uint GetId() { if ((Name & 0x80000000) == 0x80000000) + { return 0; - + } + return Name; } @@ -98,7 +100,7 @@ public async Task GetNameAsync() var count = await stream.ReadUInt16Async().ConfigureAwait(false); var builder = new StringBuilder(count); - for(int i = 0; i < count; i++) + for(var i = 0; i < count; i++) { var value = await stream.ReadUInt16Async().ConfigureAwait(false); var chr = Convert.ToChar(value); From 93ccd5a815be4e56deec52c11be410e71b5aff66 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Sun, 5 Jul 2020 20:05:08 +0100 Subject: [PATCH 08/12] Nothing changed really? --- .../Workshell.PE.Resources.csproj | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/Workshell.PE.Resources/Workshell.PE.Resources.csproj b/src/Workshell.PE.Resources/Workshell.PE.Resources.csproj index 4451230..9901425 100644 --- a/src/Workshell.PE.Resources/Workshell.PE.Resources.csproj +++ b/src/Workshell.PE.Resources/Workshell.PE.Resources.csproj @@ -1,55 +1,55 @@ - - - - netstandard2.0;net45 - false - false - Workshell.snk - Debug;Release;CI - - - - Workshell.PE.Resources - A set of classes that extends the Workshell.PE class library to help deal with the standard resource types within an executable such as bitmaps, icons, cursors etc. - https://github.com/Workshell/pe - http://img.workshell.co.uk/logo_128.png - workshell pe executable native resources - license.txt - Workshell Ltd - Workshell Ltd - https://github.com/Workshell/pe - git - 0.0.0.1 - - - - - - - ..\..\bin\debug - TRACE - - - - ..\..\bin\release - TRACE - - + + + + netstandard2.0;net45 + false + false + Workshell.snk + Debug;Release;CI + + + + Workshell.PE.Resources + A set of classes that extends the Workshell.PE class library to help deal with the standard resource types within an executable such as bitmaps, icons, cursors etc. + https://github.com/Workshell/pe + http://img.workshell.co.uk/logo_128.png + workshell pe executable native resources + license.txt + Workshell Ltd + Workshell Ltd + https://github.com/Workshell/pe + git + 0.0.0.1 + + + + + + + ..\..\bin\debug + TRACE + + + + ..\..\bin\release + TRACE + + ..\..\bin\ci TRACE;SIGNED - - - - - - - - - - + + + + + + + + + + - - - + + + From 9a9ce7fc81d8d384e210bdcc21539049aba8eee7 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Thu, 21 Jul 2022 18:32:12 +0100 Subject: [PATCH 09/12] Fixed up tests and a bix in a date/time parser. --- src/Workshell.PE/Utils.cs | 2 +- tests/Workshell.PE.Tests/Workshell.PE.Tests.csproj | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Workshell.PE/Utils.cs b/src/Workshell.PE/Utils.cs index f81a79d..d6dffb5 100644 --- a/src/Workshell.PE/Utils.cs +++ b/src/Workshell.PE/Utils.cs @@ -193,7 +193,7 @@ public static void Write(T structure, Stream stream, int size) where T : stru public static DateTime ConvertTimeDateStamp(uint timeDateStamp) { - var result = UnixEpoch.AddSeconds(timeDateStamp).Add(DateTimeOffset.Now.Offset); + var result = UnixEpoch.AddSeconds(timeDateStamp).Add(DateTimeOffset.UtcNow.Offset); return result; } diff --git a/tests/Workshell.PE.Tests/Workshell.PE.Tests.csproj b/tests/Workshell.PE.Tests/Workshell.PE.Tests.csproj index 0a56a6a..cb88f13 100644 --- a/tests/Workshell.PE.Tests/Workshell.PE.Tests.csproj +++ b/tests/Workshell.PE.Tests/Workshell.PE.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.0 + net6.0 false false Workshell.snk @@ -41,10 +41,10 @@ - - - - + + + + From 3744f8dec9fbcd5be2629261e55668628fe35283 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Fri, 19 May 2023 22:54:19 +0100 Subject: [PATCH 10/12] Version bump to new major version. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index c346e7a..56fea8a 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.1.4 \ No newline at end of file +3.0.0 \ No newline at end of file From 93aab4eeae9eb02c1c53c8b6cc78293611083eca Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Sat, 20 May 2023 00:35:50 +0100 Subject: [PATCH 11/12] Switched to using .NET6+ only to simplify things. Still dependent on System.Drawing.Common for now though. --- .../Workshell.PE.Resources.csproj | 100 ++++++++-------- .../Content/CLR/CLRMetaDataStreams.cs | 1 + .../Imports/DelayedImportAddressTables.cs | 5 + .../Content/Imports/ImportAddressTables.cs | 3 + src/Workshell.PE/Extensions/Enumerable.cs | 111 ------------------ src/Workshell.PE/Extensions/Stream.cs | 30 ++++- src/Workshell.PE/Utils.cs | 9 +- src/Workshell.PE/Workshell.PE.csproj | 8 +- tests/Workshell.PE.Tests/UtilsTests.cs | 6 +- .../Workshell.PE.Tests.csproj | 10 +- 10 files changed, 105 insertions(+), 178 deletions(-) delete mode 100644 src/Workshell.PE/Extensions/Enumerable.cs diff --git a/src/Workshell.PE.Resources/Workshell.PE.Resources.csproj b/src/Workshell.PE.Resources/Workshell.PE.Resources.csproj index 4451230..873a3e9 100644 --- a/src/Workshell.PE.Resources/Workshell.PE.Resources.csproj +++ b/src/Workshell.PE.Resources/Workshell.PE.Resources.csproj @@ -1,55 +1,55 @@ - - - - netstandard2.0;net45 - false - false - Workshell.snk - Debug;Release;CI - - - - Workshell.PE.Resources - A set of classes that extends the Workshell.PE class library to help deal with the standard resource types within an executable such as bitmaps, icons, cursors etc. - https://github.com/Workshell/pe - http://img.workshell.co.uk/logo_128.png - workshell pe executable native resources - license.txt - Workshell Ltd - Workshell Ltd - https://github.com/Workshell/pe - git - 0.0.0.1 - - - - - - - ..\..\bin\debug - TRACE - - - - ..\..\bin\release - TRACE - - + + + + net7.0;net6.0 + false + false + Workshell.snk + Debug;Release;CI + + + + Workshell.PE.Resources + A set of classes that extends the Workshell.PE class library to help deal with the standard resource types within an executable such as bitmaps, icons, cursors etc. + https://github.com/Workshell/pe + http://img.workshell.co.uk/logo_128.png + workshell pe executable native resources + license.txt + Workshell Ltd + Workshell Ltd + https://github.com/Workshell/pe + git + 0.0.0.1 + + + + + + + ..\..\bin\debug + TRACE + + + + ..\..\bin\release + TRACE + + ..\..\bin\ci TRACE;SIGNED - - - - - - - - - - + + + + + + + + + + - - - + + + diff --git a/src/Workshell.PE/Content/CLR/CLRMetaDataStreams.cs b/src/Workshell.PE/Content/CLR/CLRMetaDataStreams.cs index ecf2926..ec4ca1e 100644 --- a/src/Workshell.PE/Content/CLR/CLRMetaDataStreams.cs +++ b/src/Workshell.PE/Content/CLR/CLRMetaDataStreams.cs @@ -26,6 +26,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; + using Workshell.PE.Extensions; namespace Workshell.PE.Content diff --git a/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs b/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs index 0d7efe6..c19c487 100644 --- a/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs +++ b/src/Workshell.PE/Content/Imports/DelayedImportAddressTables.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Threading.Tasks; @@ -106,7 +107,9 @@ private static async Task GetTablesAsync(PortableExe entries.Add(entry); if (entry == 0) + { break; + } } var table = new Tuple(thunk, entries.ToArray(), dirEntry); @@ -117,7 +120,9 @@ private static async Task GetTablesAsync(PortableExe var rva = 0u; if (tables.Count > 0) + { rva = tables.MinBy(table => table.Item1).Item1; + } var imageBase = image.NTHeaders.OptionalHeader.ImageBase; var va = imageBase + rva; diff --git a/src/Workshell.PE/Content/Imports/ImportAddressTables.cs b/src/Workshell.PE/Content/Imports/ImportAddressTables.cs index d860f64..851da78 100644 --- a/src/Workshell.PE/Content/Imports/ImportAddressTables.cs +++ b/src/Workshell.PE/Content/Imports/ImportAddressTables.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Threading.Tasks; @@ -99,7 +100,9 @@ private static async Task GetTablesAsync(PortableExecutable var rva = 0u; if (tables.Count > 0) + { rva = tables.MinBy(table => table.Item1).Item1; + } var imageBase = image.NTHeaders.OptionalHeader.ImageBase; var va = imageBase + rva; diff --git a/src/Workshell.PE/Extensions/Enumerable.cs b/src/Workshell.PE/Extensions/Enumerable.cs deleted file mode 100644 index 826b037..0000000 --- a/src/Workshell.PE/Extensions/Enumerable.cs +++ /dev/null @@ -1,111 +0,0 @@ -#region License -// Copyright(c) Workshell Ltd -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Workshell.PE.Extensions -{ - internal static class EnumerableExtensions - { - public static TSource MinBy(this IEnumerable source, Func selector) - { - return source.MinBy(selector, Comparer.Default); - } - - public static TSource MinBy(this IEnumerable source, Func selector, IComparer comparer) - { - if (source == null) - throw new ArgumentNullException(nameof(source)); - - if (selector == null) - throw new ArgumentNullException(nameof(selector)); - - if (comparer == null) - throw new ArgumentNullException(nameof(comparer)); - - using (var sourceIterator = source.GetEnumerator()) - { - if (!sourceIterator.MoveNext()) - throw new InvalidOperationException("Sequence contains no elements"); - - var min = sourceIterator.Current; - var minKey = selector(min); - - while (sourceIterator.MoveNext()) - { - var candidate = sourceIterator.Current; - var candidateProjected = selector(candidate); - - if (comparer.Compare(candidateProjected, minKey) < 0) - { - min = candidate; - minKey = candidateProjected; - } - } - - return min; - } - } - - public static TSource MaxBy(this IEnumerable source, Func selector) - { - return source.MaxBy(selector, Comparer.Default); - } - - public static TSource MaxBy(this IEnumerable source, Func selector, IComparer comparer) - { - if (source == null) - throw new ArgumentNullException(nameof(source)); - - if (selector == null) - throw new ArgumentNullException(nameof(selector)); - - if (comparer == null) - throw new ArgumentNullException(nameof(comparer)); - - using (var sourceIterator = source.GetEnumerator()) - { - if (!sourceIterator.MoveNext()) - throw new InvalidOperationException("Sequence contains no elements"); - - var max = sourceIterator.Current; - var maxKey = selector(max); - - while (sourceIterator.MoveNext()) - { - var candidate = sourceIterator.Current; - var candidateProjected = selector(candidate); - - if (comparer.Compare(candidateProjected, maxKey) > 0) - { - max = candidate; - maxKey = candidateProjected; - } - } - - return max; - } - } - } -} diff --git a/src/Workshell.PE/Extensions/Stream.cs b/src/Workshell.PE/Extensions/Stream.cs index 6c2174b..ff549ad 100644 --- a/src/Workshell.PE/Extensions/Stream.cs +++ b/src/Workshell.PE/Extensions/Stream.cs @@ -46,10 +46,14 @@ public static async Task ReadStructAsync(this Stream stream, int size, boo var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (!allowSmaller && numRead < size) + { throw new IOException("Could not read all of structure from stream."); + } if (numRead < size) + { return default(T); + } return Utils.Read(buffer); } @@ -73,7 +77,9 @@ public static async Task ReadInt16Async(this Stream stream) var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (numRead < buffer.Length) + { throw new IOException("Could not read int16 from stream."); + } return Utils.ReadInt16(buffer); } @@ -84,7 +90,9 @@ public static async Task ReadInt32Async(this Stream stream) var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (numRead < buffer.Length) + { throw new IOException("Could not read int32 from stream."); + } return Utils.ReadInt32(buffer); } @@ -95,7 +103,9 @@ public static async Task ReadInt64Async(this Stream stream) var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (numRead < buffer.Length) + { throw new IOException("Could not read int64 from stream."); + } return Utils.ReadInt64(buffer); } @@ -106,7 +116,9 @@ public static async Task ReadUInt16Async(this Stream stream) var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (numRead < buffer.Length) + { throw new IOException("Could not read uint16 from stream."); + } return Utils.ReadUInt16(buffer); } @@ -117,7 +129,9 @@ public static async Task ReadUInt32Async(this Stream stream) var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (numRead < buffer.Length) + { throw new IOException("Could not read uint32 from stream."); + } return Utils.ReadUInt32(buffer); } @@ -128,7 +142,9 @@ public static async Task ReadUInt64Async(this Stream stream) var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (numRead < buffer.Length) + { throw new IOException("Could not read uint64 from stream."); + } return Utils.ReadUInt64(buffer); } @@ -143,7 +159,9 @@ public static async Task ReadStringAsync(this Stream stream) var numRead = await stream.ReadAsync(buffer, 0, buffer.Length); if (numRead < 1 || buffer[0] == 0) + { break; + } builder.Append((char) buffer[0]); } @@ -157,14 +175,18 @@ public static async Task ReadStringAsync(this Stream stream, int size, b var numRead = await stream.ReadAsync(buffer, 0, buffer.Length); if (!allowSmaller && numRead < buffer.Length) + { throw new IOException("Could not read string from stream."); - + } + var builder = new StringBuilder(256); foreach(var b in buffer) { if (b == 0) + { break; + } builder.Append((char)b); } @@ -181,7 +203,9 @@ public static async Task ReadUnicodeStringAsync(this Stream stream) var value = await ReadUInt16Async(stream).ConfigureAwait(false); if (value == 0) + { break; + } builder.Append((char)value); } @@ -198,7 +222,9 @@ public static async Task ReadUnicodeStringAsync(this Stream stream, int var value = await ReadUInt16Async(stream).ConfigureAwait(false); if (value == 0) + { break; + } builder.Append((char)value); } @@ -209,7 +235,9 @@ public static async Task ReadUnicodeStringAsync(this Stream stream, int public static async Task ReadBytesAsync(this Stream stream, int count, long offset = -1) { if (offset >= 0) + { stream.Seek(offset, SeekOrigin.Begin); + } var buffer = new byte[count]; var numRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); diff --git a/src/Workshell.PE/Utils.cs b/src/Workshell.PE/Utils.cs index f81a79d..f088998 100644 --- a/src/Workshell.PE/Utils.cs +++ b/src/Workshell.PE/Utils.cs @@ -193,7 +193,14 @@ public static void Write(T structure, Stream stream, int size) where T : stru public static DateTime ConvertTimeDateStamp(uint timeDateStamp) { - var result = UnixEpoch.AddSeconds(timeDateStamp).Add(DateTimeOffset.Now.Offset); + var result = UnixEpoch.AddSeconds(timeDateStamp); + + if (result.Kind == DateTimeKind.Utc) + { + return result; + } + + result = new DateTime(result.Year, result.Month, result.Day, result.Hour, result.Minute, result.Second, DateTimeKind.Utc); return result; } diff --git a/src/Workshell.PE/Workshell.PE.csproj b/src/Workshell.PE/Workshell.PE.csproj index f7c3026..062fa02 100644 --- a/src/Workshell.PE/Workshell.PE.csproj +++ b/src/Workshell.PE/Workshell.PE.csproj @@ -1,7 +1,7 @@  - netstandard1.6;net45 + net7.0;net6.0 false false Workshell.snk @@ -44,10 +44,4 @@ - - - - - - diff --git a/tests/Workshell.PE.Tests/UtilsTests.cs b/tests/Workshell.PE.Tests/UtilsTests.cs index 49f02a0..eac3d31 100644 --- a/tests/Workshell.PE.Tests/UtilsTests.cs +++ b/tests/Workshell.PE.Tests/UtilsTests.cs @@ -145,11 +145,11 @@ public void Write_Structure_To_Stream_Succeeds() } } - [TestCase(0U, "1970-01-01T00:00:00")] - [TestCase(1573219373U, "2019-11-08T13:22:53")] + [TestCase(0U, "1970-01-01T00:00:00Z")] + [TestCase(1573219373U, "2019-11-08T13:22:53Z")] public void ConvertTimeDateStamp_Returns_Correct_DateTime(uint input, string expectedValue) { - var parsedExpectedValue = DateTime.ParseExact(expectedValue, "yyyy-MM-ddTHH:mm:ss", null); + var parsedExpectedValue = DateTime.ParseExact(expectedValue, "yyyy-MM-ddTHH:mm:ssZ", null); var output = Utils.ConvertTimeDateStamp(input); output.Should().Be(parsedExpectedValue); diff --git a/tests/Workshell.PE.Tests/Workshell.PE.Tests.csproj b/tests/Workshell.PE.Tests/Workshell.PE.Tests.csproj index 0a56a6a..8235cf5 100644 --- a/tests/Workshell.PE.Tests/Workshell.PE.Tests.csproj +++ b/tests/Workshell.PE.Tests/Workshell.PE.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.0 + net6.0 false false Workshell.snk @@ -41,10 +41,10 @@ - - - - + + + + From da9cf7b41f31a5db8ee8c243fc483007838d5959 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Sun, 21 May 2023 00:08:28 +0100 Subject: [PATCH 12/12] Bumped version. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index c346e7a..56fea8a 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.1.4 \ No newline at end of file +3.0.0 \ No newline at end of file