/// <summary> /// Create metadata module from a stream. /// </summary> /// <param name="peStream">Stream containing portable executable image. Position zero should contain the first byte of the DOS header ("MZ").</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, the responsibility for disposal of the stream is transferred upon entry of the constructor /// unless the arguments given are invalid. /// </param> /// <exception cref="ArgumentNullException"><paramref name="peStream"/> is null.</exception> /// <exception cref="ArgumentException">The stream doesn't support read and seek operations.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="options"/> has an invalid value.</exception> /// <exception cref="BadImageFormatException"> /// <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified and the PE headers of the image are invalid. /// </exception> /// <exception cref="IOException"> /// <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified and an error occurs while reading the stream. /// </exception> public static ModuleMetadata CreateFromStream(Stream peStream, PEStreamOptions options) { if (peStream == null) { throw new ArgumentNullException(nameof(peStream)); } if (!peStream.CanRead || !peStream.CanSeek) { throw new ArgumentException( CodeAnalysisResources.StreamMustSupportReadAndSeek, nameof(peStream) ); } // Workaround of issue https://github.com/dotnet/corefx/issues/1815: if ( peStream.Length == 0 && (options & PEStreamOptions.PrefetchEntireImage) != 0 && (options & PEStreamOptions.PrefetchMetadata) != 0 ) { // throws BadImageFormatException: new PEHeaders(peStream); } // ownership of the stream is passed on PEReader: return(new ModuleMetadata(new PEReader(peStream, options))); }
public unsafe void CreateFromUnmanagedMemoryStream_Prefetcha_LeaveOpenTrue(PEStreamOptions options) { var assembly = TestResources.Basic.Members; fixed(byte *assemblyPtr = assembly) { var disposed = false; var seeked = false; var stream = new MockUnmanagedMemoryStream(assemblyPtr, assembly.LongLength) { OnDispose = _ => disposed = true, OnSeek = (_, _) => seeked = true, }; var metadata = ModuleMetadata.CreateFromStream(stream, options | PEStreamOptions.LeaveOpen); Assert.Equal(new AssemblyIdentity("Members"), metadata.Module.ReadAssemblyIdentityOrThrow()); // Disposing the metadata should not dispose the stream. metadata.Dispose(); Assert.False(disposed); stream.Dispose(); Assert.True(disposed); // We should have seeked. This stream will be viewed as a normal stream since we're prefetching // everything. Assert.True(seeked); } }
/// <summary> /// Returns the portable PDB reader for the assembly path /// </summary> /// <param name="assemblyPath">file path of the assembly or null if the module is in-memory or dynamic</param> /// <param name="isFileLayout">type of in-memory PE layout, if true, file based layout otherwise, loaded layout</param> /// <param name="peStream">in-memory PE stream or null</param> /// <returns>symbol file or null</returns> /// <remarks> /// Assumes that neither PE image nor PDB loaded into memory can be unloaded or moved around. /// </remarks> public ISymbolFile OpenSymbolFile(string assemblyPath, bool isFileLayout, Stream peStream) { if (assemblyPath == null && peStream == null) { throw new ArgumentNullException(nameof(assemblyPath)); } if (peStream is not null && !peStream.CanSeek) { throw new ArgumentException(nameof(peStream)); } PEStreamOptions options = isFileLayout ? PEStreamOptions.Default : PEStreamOptions.IsLoadedImage; if (peStream == null) { peStream = Utilities.TryOpenFile(assemblyPath); if (peStream == null) { return(null); } options = PEStreamOptions.Default; } try { using (var peReader = new PEReader(peStream, options)) { ReadPortableDebugTableEntries(peReader, out DebugDirectoryEntry codeViewEntry, out DebugDirectoryEntry embeddedPdbEntry); // First try .pdb file specified in CodeView data (we prefer .pdb file on disk over embedded PDB // since embedded PDB needs decompression which is less efficient than memory-mapping the file). if (codeViewEntry.DataSize != 0) { var result = TryOpenReaderFromCodeView(peReader, codeViewEntry, assemblyPath); if (result != null) { return(result); } } // if it failed try Embedded Portable PDB (if available): if (embeddedPdbEntry.DataSize != 0) { return(TryOpenReaderFromEmbeddedPdb(peReader, embeddedPdbEntry)); } } } catch (Exception e) when(e is BadImageFormatException || e is IOException) { // nop } return(null); }
public UniversalAssemblyResolver(string mainAssemblyFileName, bool throwOnError, string targetFramework, PEStreamOptions options = PEStreamOptions.Default) { this.options = options; this.TargetFramework = targetFramework ?? string.Empty; this.mainAssemblyFileName = mainAssemblyFileName; this.baseDirectory = Path.GetDirectoryName(mainAssemblyFileName); this.throwOnError = throwOnError; if (string.IsNullOrWhiteSpace(this.baseDirectory)) { this.baseDirectory = Environment.CurrentDirectory; } AddSearchDirectory(baseDirectory); }
/// <summary> /// Create metadata module from a stream. /// </summary> /// <param name="peStream">Stream containing portable executable image. Position zero should contain the first byte of the DOS header ("MZ").</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, the responsibility for disposal of the stream is transferred upon entry of the constructor /// unless the arguments given are invalid. /// </param> /// <exception cref="ArgumentNullException"><paramref name="peStream"/> is null.</exception> /// <exception cref="ArgumentException">The stream doesn't support read and seek operations.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="options"/> has an invalid value.</exception> /// <exception cref="BadImageFormatException"> /// <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified and the PE headers of the image are invalid. /// </exception> /// <exception cref="IOException"> /// <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified and an error occurs while reading the stream. /// </exception> public static ModuleMetadata CreateFromStream(Stream peStream, PEStreamOptions options) { if (peStream == null) { throw new ArgumentNullException(nameof(peStream)); } if (!peStream.CanRead || !peStream.CanSeek) { throw new ArgumentException(CodeAnalysisResources.StreamMustSupportReadAndSeek, nameof(peStream)); } // ownership of the stream is passed on PEReader: return(new ModuleMetadata(new PEReader(peStream, options))); }
LoadResult LoadAssembly(Stream stream, PEStreamOptions streamOptions, bool applyWinRTProjections) { MetadataReaderOptions options = applyWinRTProjections ? MetadataReaderOptions.ApplyWindowsRuntimeProjections : MetadataReaderOptions.None; PEFile module = new PEFile(fileName, stream, streamOptions, metadataOptions: options); debugInfoProvider = LoadDebugInfo(module); lock (loadedAssemblies) { loadedAssemblies.Add(module, this); } return(new LoadResult(module)); }
public UniversalAssemblyResolver(string mainAssemblyFileName, bool throwOnError, string targetFramework, PEStreamOptions streamOptions = PEStreamOptions.Default, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default) { this.streamOptions = streamOptions; this.metadataOptions = metadataOptions; this.targetFramework = targetFramework ?? string.Empty; (targetFrameworkIdentifier, targetFrameworkVersion) = ParseTargetFramework(this.targetFramework); this.mainAssemblyFileName = mainAssemblyFileName; this.baseDirectory = Path.GetDirectoryName(mainAssemblyFileName); this.throwOnError = throwOnError; if (string.IsNullOrWhiteSpace(this.baseDirectory)) { this.baseDirectory = Environment.CurrentDirectory; } AddSearchDirectory(baseDirectory); }
/// <summary> /// Create metadata module from a stream. /// </summary> /// <param name="peStream">Stream containing portable executable image. Position zero should contain the first byte of the DOS header ("MZ").</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, the responsibility for disposal of the stream is transferred upon entry of the constructor /// unless the arguments given are invalid. /// </param> /// <exception cref="ArgumentNullException"><paramref name="peStream"/> is null.</exception> /// <exception cref="ArgumentException">The stream doesn't support read and seek operations.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="options"/> has an invalid value.</exception> /// <exception cref="BadImageFormatException"> /// <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified and the PE headers of the image are invalid. /// </exception> /// <exception cref="IOException"> /// <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified and an error occurs while reading the stream. /// </exception> public static ModuleMetadata CreateFromStream(Stream peStream, PEStreamOptions options) { if (peStream == null) { throw new ArgumentNullException(nameof(peStream)); } if (!peStream.CanRead || !peStream.CanSeek) { throw new ArgumentException(CodeAnalysisResources.StreamMustSupportReadAndSeek, nameof(peStream)); } var prefetch = (options & (PEStreamOptions.PrefetchEntireImage | PEStreamOptions.PrefetchMetadata)) != 0; // If this stream is an UnmanagedMemoryStream, we can heavily optimize creating the metadata by directly // accessing the underlying memory. Note: we can only do this if the caller asked us not to prefetch the // metadata from the stream. In that case, we want to fall through below and have the PEReader read // everything into a copy immediately. If, however, we are allowed to be lazy, we can create an efficient // metadata that is backed directly by the memory that is backed in, and which will release that memory (if // requested) once it is done with it. if (!prefetch && peStream is UnmanagedMemoryStream unmanagedMemoryStream) { unsafe { Action?onDispose = options.HasFlag(PEStreamOptions.LeaveOpen) ? null : unmanagedMemoryStream.Dispose; return(CreateFromImage( unmanagedMemoryStream.PositionPointer, (int)Math.Min(unmanagedMemoryStream.Length, int.MaxValue), onDispose)); } } // Workaround of issue https://github.com/dotnet/corefx/issues/1815: if (peStream.Length == 0 && (options & PEStreamOptions.PrefetchEntireImage) != 0 && (options & PEStreamOptions.PrefetchMetadata) != 0) { // throws BadImageFormatException: new PEHeaders(peStream); } // ownership of the stream is passed on PEReader: return(new ModuleMetadata(new PEReader(peStream, options), onDispose: null)); }
public MyAssemblyResolver( string mainAssemblyFileName, bool throwOnError, string targetFramework, PEStreamOptions streamOptions = PEStreamOptions.Default, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default) { _streamOptions = streamOptions; _metadataOptions = metadataOptions; _baseAssemblyResolver = new UniversalAssemblyResolver( mainAssemblyFileName, throwOnError, targetFramework, streamOptions, metadataOptions ); }
public UniversalAssemblyResolver(string?mainAssemblyFileName, bool throwOnError, string?targetFramework, string?runtimePack = null, PEStreamOptions streamOptions = PEStreamOptions.Default, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default) { this.mainAssemblyFileName = mainAssemblyFileName; this.throwOnError = throwOnError; this.streamOptions = streamOptions; this.metadataOptions = metadataOptions; this.targetFramework = targetFramework ?? string.Empty; this.runtimePack = runtimePack ?? "Microsoft.NETCore.App"; (targetFrameworkIdentifier, targetFrameworkVersion) = ParseTargetFramework(this.targetFramework); this.dotNetCorePathFinder = new Lazy <DotNetCorePathFinder>(InitDotNetCorePathFinder); if (mainAssemblyFileName != null) { string baseDirectory = Path.GetDirectoryName(mainAssemblyFileName); if (string.IsNullOrWhiteSpace(this.baseDirectory)) { this.baseDirectory = Environment.CurrentDirectory; } AddSearchDirectory(baseDirectory); } }
LoadResult LoadAssembly(Stream stream, PEStreamOptions streamOptions) { MetadataReaderOptions options; if (DecompilerSettingsPanel.CurrentDecompilerSettings.ApplyWindowsRuntimeProjections) { options = MetadataReaderOptions.ApplyWindowsRuntimeProjections; } else { options = MetadataReaderOptions.None; } PEFile module = new PEFile(fileName, stream, streamOptions, metadataOptions: options); if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) { try { debugInfoProvider = DebugInfoUtils.FromFile(module, PdbFileOverride) ?? DebugInfoUtils.LoadSymbols(module); } catch (IOException) { } catch (UnauthorizedAccessException) { } catch (InvalidOperationException) { // ignore any errors during symbol loading } } lock (loadedAssemblies) { loadedAssemblies.Add(module, this); } return(new LoadResult(module)); }
LoadResult LoadAssembly(Stream stream, PEStreamOptions streamOptions) { MetadataReaderOptions options; if (DecompilerSettingsPanel.CurrentDecompilerSettings.ApplyWindowsRuntimeProjections) { options = MetadataReaderOptions.ApplyWindowsRuntimeProjections; } else { options = MetadataReaderOptions.None; } PEFile module = new PEFile(fileName, stream, streamOptions, metadataOptions: options); debugInfoProvider = LoadDebugInfo(module); lock (loadedAssemblies) { loadedAssemblies.Add(module, this); } return(new LoadResult(module)); }
/// <summary> /// Resolves the specified full assembly name. /// </summary> /// <param name="reference">A reference with details about the assembly.</param> /// <param name="parent">The parent of the reference.</param> /// <param name="input">The directories potentially containing the assemblies.</param> /// <param name="framework">The framework we are processing for.</param> /// <param name="parameters">Parameters to provide to the reflection system..</param> /// <returns>The assembly definitions.</returns> public static PEFile?Resolve(this IAssemblyReference reference, IModule parent, InputAssembliesGroup input, NuGetFramework framework, PEStreamOptions parameters = PEStreamOptions.PrefetchMetadata) { var fileName = GetFileName(reference, parent, input, framework); return(string.IsNullOrWhiteSpace(fileName) ? null : new PEFile(fileName, parameters)); }
public PEFile(string fileName, PEStreamOptions streamOptions = PEStreamOptions.Default, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default) : this(fileName, new PEReader(new FileStream(fileName, FileMode.Open, FileAccess.Read), streamOptions), metadataOptions) { }
/// <summary> /// Creates a Portable Executable reader over a PE image stored in a stream beginning at its current position and ending at the end of the stream. /// </summary> /// <param name="peStream">PE image stream.</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, ownership of the stream is transferred to the <see cref="PEReader"/> /// upon successful argument validation. It will be disposed by the <see cref="PEReader"/> and the caller must not manipulate it. /// /// Unless <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified no data /// is read from the stream during the construction of the <see cref="PEReader"/>. Furthermore, the stream must not be manipulated /// by caller while the <see cref="PEReader"/> is alive and undisposed. /// /// If <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/>, the <see cref="PEReader"/> /// will have read all of the data requested during construction. As such, if <see cref="PEStreamOptions.LeaveOpen"/> is also /// specified, the caller retains full ownership of the stream and is assured that it will not be manipulated by the <see cref="PEReader"/> /// after construction. /// </param> /// <exception cref="ArgumentNullException"><paramref name="peStream"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="options"/> has an invalid value.</exception> /// <exception cref="BadImageFormatException"> /// <see cref="PEStreamOptions.PrefetchMetadata"/> is specified and the PE headers of the image are invalid. /// </exception> public PEReader(Stream peStream, PEStreamOptions options) : this(peStream, options, 0) { }
/// <summary> /// Creates a Portable Executable reader over a PE image of the given size beginning at the stream's current position. /// </summary> /// <param name="peStream">PE image stream.</param> /// <param name="size">PE image size.</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, ownership of the stream is transferred to the <see cref="PEReader"/> /// upon successful argument validation. It will be disposed by the <see cref="PEReader"/> and the caller must not manipulate it. /// /// Unless <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified no data /// is read from the stream during the construction of the <see cref="PEReader"/>. Furthermore, the stream must not be manipulated /// by caller while the <see cref="PEReader"/> is alive and undisposed. /// /// If <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/>, the <see cref="PEReader"/> /// will have read all of the data requested during construction. As such, if <see cref="PEStreamOptions.LeaveOpen"/> is also /// specified, the caller retains full ownership of the stream and is assured that it will not be manipulated by the <see cref="PEReader"/> /// after construction. /// </param> /// <exception cref="ArgumentOutOfRangeException">Size is negative or extends past the end of the stream.</exception> /// <exception cref="IOException">Error reading from the stream (only when prefetching data).</exception> public unsafe PEReader(Stream peStream, PEStreamOptions options, int size) { if (peStream == null) { throw new ArgumentNullException(nameof(peStream)); } if (!peStream.CanRead || !peStream.CanSeek) { throw new ArgumentException(SR.StreamMustSupportReadAndSeek, nameof(peStream)); } if (!options.IsValid()) { throw new ArgumentOutOfRangeException(nameof(options)); } long start = peStream.Position; int actualSize = StreamExtensions.GetAndValidateSize(peStream, size, nameof(peStream)); bool closeStream = true; try { bool isFileStream = FileStreamReadLightUp.IsFileStream(peStream); if ((options & (PEStreamOptions.PrefetchMetadata | PEStreamOptions.PrefetchEntireImage)) == 0) { _peImage = new StreamMemoryBlockProvider(peStream, start, actualSize, isFileStream, (options & PEStreamOptions.LeaveOpen) != 0); closeStream = false; } else { // Read in the entire image or metadata blob: if ((options & PEStreamOptions.PrefetchEntireImage) != 0) { var imageBlock = StreamMemoryBlockProvider.ReadMemoryBlockNoLock(peStream, isFileStream, start, actualSize); _lazyImageBlock = imageBlock; _peImage = new ExternalMemoryBlockProvider(imageBlock.Pointer, imageBlock.Size); // if the caller asked for metadata initialize the PE headers (calculates metadata offset): if ((options & PEStreamOptions.PrefetchMetadata) != 0) { InitializePEHeaders(); } } else { // The peImage is left null, but the lazyMetadataBlock is initialized up front. _lazyPEHeaders = new PEHeaders(peStream); _lazyMetadataBlock = StreamMemoryBlockProvider.ReadMemoryBlockNoLock(peStream, isFileStream, _lazyPEHeaders.MetadataStartOffset, _lazyPEHeaders.MetadataSize); } // We read all we need, the stream is going to be closed. } } finally { if (closeStream && (options & PEStreamOptions.LeaveOpen) == 0) { peStream.Dispose(); } } }
/// <summary> /// Creates a single-module assembly. /// </summary> /// <param name="peStream">Manifest module PE image stream.</param> /// <param name="options">False to close the stream upon disposal of the metadata.</param> /// <exception cref="BadImageFormatException">The PE image format is invalid.</exception> public static AssemblyMetadata CreateFromImageStream(Stream peStream, PEStreamOptions options) { return(Create(ModuleMetadata.CreateFromImageStream(peStream, options))); }
/// <summary> /// Creates a Portable Executable reader over a PE image of the given size beginning at the stream's current position. /// </summary> /// <param name="peStream">PE image stream.</param> /// <param name="size">PE image size.</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, ownership of the stream is transferred to the <see cref="PEReader"/> /// upon successful argument validation. It will be disposed by the <see cref="PEReader"/> and the caller must not manipulate it. /// /// Unless <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified no data /// is read from the stream during the construction of the <see cref="PEReader"/>. Furthermore, the stream must not be manipulated /// by caller while the <see cref="PEReader"/> is alive and undisposed. /// /// If <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/>, the <see cref="PEReader"/> /// will have read all of the data requested during construction. As such, if <see cref="PEStreamOptions.LeaveOpen"/> is also /// specified, the caller retains full ownership of the stream and is assured that it will not be manipulated by the <see cref="PEReader"/> /// after construction. /// </param> /// <exception cref="ArgumentOutOfRangeException">Size is negative or extends past the end of the stream.</exception> public PEReader(Stream peStream, PEStreamOptions options, int size) : this(peStream, options, (int?)size) { }
/// <summary> /// Creates a Portable Executable reader over a PE image stored in a stream beginning at its current position and ending at the end of the stream. /// </summary> /// <param name="peStream">PE image stream.</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, ownership of the stream is transferred to the <see cref="PEReader"/> /// upon successful argument validation. It will be disposed by the <see cref="PEReader"/> and the caller must not manipulate it. /// /// Unless <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified no data /// is read from the stream during the construction of the <see cref="PEReader"/>. Furthermore, the stream must not be manipulated /// by caller while the <see cref="PEReader"/> is alive and undisposed. /// /// If <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/>, the <see cref="PEReader"/> /// will have read all of the data requested during construction. As such, if <see cref="PEStreamOptions.LeaveOpen"/> is also /// specified, the caller retains full ownership of the stream and is assured that it will not be manipulated by the <see cref="PEReader"/> /// after construction. /// </param> /// <exception cref="ArgumentNullException"><paramref name="peStream"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="options"/> has an invalid value.</exception> /// <exception cref="BadImageFormatException"> /// <see cref="PEStreamOptions.PrefetchMetadata"/> is specified and the PE headers of the image are invalid. /// </exception> public PEReader(Stream peStream, PEStreamOptions options) : this(peStream, options, (int?)null) { }
/// <summary> /// Creates a Portable Executable reader over a PE image of the given size beginning at the stream's current position. /// </summary> /// <param name="peStream">PE image stream.</param> /// <param name="size">PE image size.</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, ownership of the stream is transferred to the <see cref="PEReader"/> /// upon successful argument validation. It will be disposed by the <see cref="PEReader"/> and the caller must not manipulate it. /// /// Unless <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified no data /// is read from the stream during the construction of the <see cref="PEReader"/>. Furthermore, the stream must not be manipulated /// by caller while the <see cref="PEReader"/> is alive and undisposed. /// /// If <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/>, the <see cref="PEReader"/> /// will have read all of the data requested during construction. As such, if <see cref="PEStreamOptions.LeaveOpen"/> is also /// specified, the caller retains full ownership of the stream and is assured that it will not be manipulated by the <see cref="PEReader"/> /// after construction. /// </param> /// <exception cref="ArgumentOutOfRangeException">Size is negative or extends past the end of the stream.</exception> /// <exception cref="IOException">Error reading from the stream (only when prefetching data).</exception> /// <exception cref="BadImageFormatException"><see cref="PEStreamOptions.PrefetchMetadata"/> is specified and the PE headers of the image are invalid.</exception> public unsafe PEReader(Stream peStream, PEStreamOptions options, int size) { if (peStream == null) { throw new ArgumentNullException(nameof(peStream)); } if (!peStream.CanRead || !peStream.CanSeek) { throw new ArgumentException(SR.StreamMustSupportReadAndSeek, nameof(peStream)); } if (!options.IsValid()) { throw new ArgumentOutOfRangeException(nameof(options)); } IsLoadedImage = (options & PEStreamOptions.IsLoadedImage) != 0; long start = peStream.Position; int actualSize = StreamExtensions.GetAndValidateSize(peStream, size, nameof(peStream)); bool closeStream = true; try { bool isFileStream = FileStreamReadLightUp.IsFileStream(peStream); if ((options & (PEStreamOptions.PrefetchMetadata | PEStreamOptions.PrefetchEntireImage)) == 0) { _peImage = new StreamMemoryBlockProvider(peStream, start, actualSize, isFileStream, (options & PEStreamOptions.LeaveOpen) != 0); closeStream = false; } else { // Read in the entire image or metadata blob: if ((options & PEStreamOptions.PrefetchEntireImage) != 0) { var imageBlock = StreamMemoryBlockProvider.ReadMemoryBlockNoLock(peStream, isFileStream, start, actualSize); _lazyImageBlock = imageBlock; _peImage = new ExternalMemoryBlockProvider(imageBlock.Pointer, imageBlock.Size); // if the caller asked for metadata initialize the PE headers (calculates metadata offset): if ((options & PEStreamOptions.PrefetchMetadata) != 0) { InitializePEHeaders(); } } else { // The peImage is left null, but the lazyMetadataBlock is initialized up front. _lazyPEHeaders = new PEHeaders(peStream); _lazyMetadataBlock = StreamMemoryBlockProvider.ReadMemoryBlockNoLock(peStream, isFileStream, _lazyPEHeaders.MetadataStartOffset, _lazyPEHeaders.MetadataSize); } // We read all we need, the stream is going to be closed. } } finally { if (closeStream && (options & PEStreamOptions.LeaveOpen) == 0) { peStream.Dispose(); } } }
/// <summary> /// Create metadata module from a stream. /// </summary> /// <param name="peStream">Stream containing portable executable image. Position zero should contain the first byte of the DOS header ("MZ").</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, the responsibility for disposal of the stream is transferred upon entry of the constructor /// unless the arguments given are invalid. /// </param> /// <exception cref="BadImageFormatException"><paramref name="peStream"/> is not valid portable executable image containing CLI metadata</exception> /// <exception cref="ArgumentException">The stream doesn't support read and seek operations.</exception> /// <exception cref="ArgumentNullException"><paramref name="peStream"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="options"/> has an invalid value.</exception> public static ModuleMetadata CreateFromImageStream(Stream peStream, PEStreamOptions options) { if (peStream == null) { throw new ArgumentNullException("peStream"); } if (!peStream.CanRead || !peStream.CanSeek) { throw new ArgumentException(CodeAnalysisResources.StreamMustSupportReadAndSeek, "peImage"); } // ownership of the stream is passed on PEReader: return new ModuleMetadata(new PEReader(peStream, options)); }
public PEFile(string fileName, Stream stream, PEStreamOptions options = PEStreamOptions.Default) : this(fileName, new PEReader(stream, options)) { }
public PEFile(string fileName, PEStreamOptions options = PEStreamOptions.Default) : this(fileName, new PEReader(new FileStream(fileName, FileMode.Open, FileAccess.Read), options)) { }
public static bool IsValid(this PEStreamOptions options) { return((options & ~(PEStreamOptions.LeaveOpen | PEStreamOptions.PrefetchEntireImage | PEStreamOptions.PrefetchMetadata)) == 0); }
public PEFile(string fileName, Stream stream, PEStreamOptions streamOptions = PEStreamOptions.Default, MetadataReaderOptions metadataOptions = MetadataReaderOptions.Default) : this(fileName, new PEReader(stream, streamOptions), metadataOptions) { }
private unsafe PEReader(Stream peStream, PEStreamOptions options, int?sizeOpt) { if (peStream == null) { throw new ArgumentNullException("peStream"); } if (!peStream.CanRead || !peStream.CanSeek) { throw new ArgumentException(MetadataResources.StreamMustSupportReadAndSeek, "peStream"); } if (!options.IsValid()) { throw new ArgumentOutOfRangeException("options"); } long start = peStream.Position; int size = PEBinaryReader.GetAndValidateSize(peStream, sizeOpt); bool closeStream = true; try { bool isFileStream = FileStreamReadLightUp.IsFileStream(peStream); if ((options & (PEStreamOptions.PrefetchMetadata | PEStreamOptions.PrefetchEntireImage)) == 0) { this.peImage = new StreamMemoryBlockProvider(peStream, start, size, isFileStream, (options & PEStreamOptions.LeaveOpen) != 0); closeStream = false; } else { // Read in the entire image or metadata blob: if ((options & PEStreamOptions.PrefetchEntireImage) != 0) { var imageBlock = StreamMemoryBlockProvider.ReadMemoryBlockNoLock(peStream, isFileStream, 0, (int)Math.Min(peStream.Length, int.MaxValue)); this.lazyImageBlock = imageBlock; this.peImage = new ExternalMemoryBlockProvider(imageBlock.Pointer, imageBlock.Size); // if the caller asked for metadata initialize the PE headers (calculates metadata offset): if ((options & PEStreamOptions.PrefetchMetadata) != 0) { InitializePEHeaders(); } } else { // The peImage is left null, but the lazyMetadataBlock is initialized up front. this.lazyPEHeaders = new PEHeaders(peStream); this.lazyMetadataBlock = StreamMemoryBlockProvider.ReadMemoryBlockNoLock(peStream, isFileStream, lazyPEHeaders.MetadataStartOffset, lazyPEHeaders.MetadataSize); } // We read all we need, the stream is going to be closed. } } finally { if (closeStream && (options & PEStreamOptions.LeaveOpen) == 0) { peStream.Dispose(); } } }
/// <summary> /// Constructs a PEImage class for a given PE image (dll/exe) in memory. /// </summary> /// <param name="stream">A Stream that contains a PE image at its 0th offset. This stream must be seekable.</param> /// <param name="leaveOpen">Whether or not to leave the stream open, if this is set to false stream will be /// disposed when this object is.</param> /// <param name="isVirtual">Whether stream points to a PE image mapped into an address space (such as in a live process or crash dump).</param> public PEImage(Stream stream, bool leaveOpen, bool isVirtual) { _isVirtual = isVirtual; _stream = stream ?? throw new ArgumentNullException(nameof(stream)); if (!stream.CanSeek) { throw new ArgumentException($"{nameof(stream)} is not seekable."); } ushort dosHeaderMagic = Read <ushort>(0); if (dosHeaderMagic != ExpectedDosHeaderMagic) { if (!leaveOpen) { stream.Dispose(); } return; } int peHeaderOffset = Read <int>(PESignatureOffsetLocation); if (peHeaderOffset == 0) { if (!leaveOpen) { stream.Dispose(); } return; } uint peSignature = Read <uint>(peHeaderOffset); if (peSignature != ExpectedPESignature) { if (!leaveOpen) { stream.Dispose(); } return; } SeekTo(0); PEStreamOptions options = PEStreamOptions.Default; if (leaveOpen) { options |= PEStreamOptions.LeaveOpen; } if (isVirtual) { options |= PEStreamOptions.IsLoadedImage; } try { var reader = new PEReader(stream, options); _peHeaders = reader.PEHeaders; Reader = reader; } catch (BadImageFormatException) { } catch (EndOfStreamException) { } }
/// <summary> /// Creates a Portable Executable reader over a PE image stored in a stream beginning at its current position and ending at the end of the stream. /// </summary> /// <param name="peStream">PE image stream.</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, ownership of the stream is transferred to the <see cref="PEReader"/> /// upon successful argument validation. It will be disposed by the <see cref="PEReader"/> and the caller must not manipulate it. /// /// Unless <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified no data /// is read from the stream during the construction of the <see cref="PEReader"/>. Furthermore, the stream must not be manipulated /// by caller while the <see cref="PEReader"/> is alive and undisposed. /// /// If <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/>, the <see cref="PEReader"/> /// will have read all of the data requested during construction. As such, if <see cref="PEStreamOptions.LeaveOpen"/> is also /// specified, the caller retains full ownership of the stream and is assured that it will not be manipulated by the <see cref="PEReader"/> /// after construction. /// </param> /// <exception cref="ArgumentNullException"><paramref name="peStream"/> is null.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="options"/> has an invalid value.</exception> /// <exception cref="IOException">Error reading from the stream (only when prefetching data).</exception> /// <exception cref="BadImageFormatException"><see cref="PEStreamOptions.PrefetchMetadata"/> is specified and the PE headers of the image are invalid.</exception> public PEReader(Stream peStream, PEStreamOptions options) : this(peStream, options, 0) { }
/// <summary> /// Create metadata module from a stream. /// </summary> /// <param name="peStream">Stream containing portable executable image. Position zero should contain the first byte of the DOS header ("MZ").</param> /// <param name="options"> /// Options specifying how sections of the PE image are read from the stream. /// Unless <see cref="PEStreamOptions.LeaveOpen"/> is specified, the responsibility for disposal of the stream is transferred upon entry of the constructor /// unless the arguments given are invalid. /// </param> /// <exception cref="ArgumentNullException"><paramref name="peStream"/> is null.</exception> /// <exception cref="ArgumentException">The stream doesn't support read and seek operations.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="options"/> has an invalid value.</exception> /// <exception cref="BadImageFormatException"> /// <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified and the PE headers of the image are invalid. /// </exception> /// <exception cref="IOException"> /// <see cref="PEStreamOptions.PrefetchMetadata"/> or <see cref="PEStreamOptions.PrefetchEntireImage"/> is specified and an error occurs while reading the stream. /// </exception> public static ModuleMetadata CreateFromStream(Stream peStream, PEStreamOptions options) { if (peStream == null) { throw new ArgumentNullException(nameof(peStream)); } if (!peStream.CanRead || !peStream.CanSeek) { throw new ArgumentException(CodeAnalysisResources.StreamMustSupportReadAndSeek, nameof(peStream)); } // Workaround of issue https://github.com/dotnet/corefx/issues/1815: if (peStream.Length == 0 && (options & PEStreamOptions.PrefetchEntireImage) != 0 && (options & PEStreamOptions.PrefetchMetadata) != 0) { // throws BadImageFormatException: new PEHeaders(peStream); } // ownership of the stream is passed on PEReader: return new ModuleMetadata(new PEReader(peStream, options)); }
/// <summary> /// Creates a single-module assembly. /// </summary> /// <param name="peStream">Manifest module PE image stream.</param> /// <param name="options">False to close the stream upon disposal of the metadata.</param> /// <exception cref="BadImageFormatException">The PE image format is invalid.</exception> public static AssemblyMetadata CreateFromStream(Stream peStream, PEStreamOptions options) { return Create(ModuleMetadata.CreateFromStream(peStream, options)); }