From e94eb917395e50c74ea363a79df3514538989daa Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 16 Jan 2025 22:13:21 +0100 Subject: [PATCH] Fix #3372: Fix loading a DLL that contains byte sequences matching ZIP central directory. --- .../FileLoaders/FileLoaderRegistry.cs | 3 +- .../FileLoaders/PEFileLoader.cs | 50 +++++++++++++++++++ ICSharpCode.ILSpyX/LoadedAssembly.cs | 7 +-- 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 ICSharpCode.ILSpyX/FileLoaders/PEFileLoader.cs diff --git a/ICSharpCode.ILSpyX/FileLoaders/FileLoaderRegistry.cs b/ICSharpCode.ILSpyX/FileLoaders/FileLoaderRegistry.cs index 8117b4b940..a6a264372a 100644 --- a/ICSharpCode.ILSpyX/FileLoaders/FileLoaderRegistry.cs +++ b/ICSharpCode.ILSpyX/FileLoaders/FileLoaderRegistry.cs @@ -42,7 +42,8 @@ public FileLoaderRegistry() Register(new XamarinCompressedFileLoader()); Register(new WebCilFileLoader()); Register(new MetadataFileLoader()); - Register(new BundleFileLoader()); + Register(new BundleFileLoader()); // bundles are PE files with a special signature, prefer over normal PE files + Register(new PEFileLoader()); // prefer PE format over archives, because ZIP has no fixed header Register(new ArchiveFileLoader()); } } diff --git a/ICSharpCode.ILSpyX/FileLoaders/PEFileLoader.cs b/ICSharpCode.ILSpyX/FileLoaders/PEFileLoader.cs new file mode 100644 index 0000000000..d9014baee6 --- /dev/null +++ b/ICSharpCode.ILSpyX/FileLoaders/PEFileLoader.cs @@ -0,0 +1,50 @@ +// Copyright (c) 2024 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System.IO; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using System.Threading.Tasks; + +using ICSharpCode.Decompiler.Metadata; + +namespace ICSharpCode.ILSpyX.FileLoaders +{ + public sealed class PEFileLoader : IFileLoader + { + public async Task Load(string fileName, Stream stream, FileLoadContext context) + { + if (stream.Length < 2 || stream.ReadByte() != 'M' || stream.ReadByte() != 'Z') + { + return null; + } + + return await LoadPEFile(fileName, stream, context).ConfigureAwait(false); + } + + public static Task LoadPEFile(string fileName, Stream stream, FileLoadContext context) + { + MetadataReaderOptions options = context.ApplyWinRTProjections + ? MetadataReaderOptions.ApplyWindowsRuntimeProjections + : MetadataReaderOptions.None; + stream.Position = 0; + PEFile module = new PEFile(fileName, stream, PEStreamOptions.PrefetchEntireImage | PEStreamOptions.LeaveOpen, metadataOptions: options); + return Task.FromResult(new LoadResult { MetadataFile = module }); + } + } +} diff --git a/ICSharpCode.ILSpyX/LoadedAssembly.cs b/ICSharpCode.ILSpyX/LoadedAssembly.cs index 26c063e5d9..64fca7a556 100644 --- a/ICSharpCode.ILSpyX/LoadedAssembly.cs +++ b/ICSharpCode.ILSpyX/LoadedAssembly.cs @@ -358,12 +358,7 @@ async Task LoadAsync(Task? streamTask) stream.Position = 0; try { - MetadataReaderOptions options = applyWinRTProjections - ? MetadataReaderOptions.ApplyWindowsRuntimeProjections - : MetadataReaderOptions.None; - - PEFile module = new PEFile(fileName, stream, PEStreamOptions.PrefetchEntireImage, metadataOptions: options); - result = new LoadResult { MetadataFile = module }; + result = await PEFileLoader.LoadPEFile(fileName, stream, settings).ConfigureAwait(false); } catch (Exception ex) {