From 63e4fb433191e7c8b8ff61446c8dd69f76f3f058 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Fri, 11 Oct 2019 10:42:38 +0100 Subject: [PATCH] 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); }