/// <summary> /// Creates a Portable Executable reader over a PE image stored in memory. /// </summary> /// <param name="peImage">Pointer to the start of the PE image.</param> /// <param name="size">The size of the PE image.</param> /// <exception cref="ArgumentNullException"><paramref name="peImage"/> is <see cref="IntPtr.Zero"/>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="size"/> is negative.</exception> /// <remarks> /// The memory is owned by the caller and not released on disposal of the <see cref="PEReader"/>. /// The caller is responsible for keeping the memory alive and unmodified throughout the lifetime of the <see cref="PEReader"/>. /// The content of the image is not read during the construction of the <see cref="PEReader"/> /// </remarks> public unsafe PEReader(byte* peImage, int size) { if (peImage == null) { throw new ArgumentNullException(nameof(peImage)); } if (size < 0) { throw new ArgumentOutOfRangeException(nameof(size)); } _peImage = new ExternalMemoryBlockProvider(peImage, size); }
/// <summary> /// Disposes all memory allocated by the reader. /// </summary> /// <remarks> /// <see cref="Dispose"/> can be called multiple times (but not in parallel). /// It is not safe to call <see cref="Dispose"/> in parallel with any other operation on the <see cref="PEReader"/> /// or reading from <see cref="PEMemoryBlock"/>s retrieved from the reader. /// </remarks> public void Dispose() { _peImage?.Dispose(); _peImage = null; _lazyImageBlock?.Dispose(); _lazyImageBlock = null; _lazyMetadataBlock?.Dispose(); _lazyMetadataBlock = null; var peSectionBlocks = _lazyPESectionBlocks; if (peSectionBlocks != null) { foreach (var block in peSectionBlocks) { block?.Dispose(); } _lazyPESectionBlocks = null; } }
/// <summary> /// Creates a Portable Executable reader over a PE image stored in a byte array. /// </summary> /// <param name="peImage">PE image.</param> /// <remarks> /// The content of the image is not read during the construction of the <see cref="PEReader"/> /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="peImage"/> is null.</exception> public PEReader(ImmutableArray<byte> peImage) { if (peImage.IsDefault) { throw new ArgumentNullException(nameof(peImage)); } _peImage = new ByteArrayMemoryProvider(peImage); }
/// <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(); } } }
private MetadataReaderProvider(MemoryBlockProvider blockProvider) { Debug.Assert(blockProvider != null); _blockProviderOpt = blockProvider; }
/// <summary> /// Disposes all memory allocated by the reader. /// </summary> /// <remarks> /// <see cref="Dispose"/> can be called multiple times (but not in parallel). /// It is not safe to call <see cref="Dispose"/> in parallel with any other operation on the <see cref="MetadataReaderProvider"/> /// or reading from the underlying memory. /// </remarks> public void Dispose() { _blockProviderOpt?.Dispose(); _blockProviderOpt = null; _lazyMetadataBlock?.Dispose(); _lazyMetadataBlock = null; }
/// <summary> /// Disposes all memory allocated by the reader. /// </summary> /// <remarks> /// <see cref="Dispose"/> can be called multiple times (but not in parallel). /// It is not safe to call <see cref="Dispose"/> in parallel with any other operation on the <see cref="PEReader"/> /// or reading from <see cref="PEMemoryBlock"/>s retrieved from the reader. /// </remarks> public void Dispose() { var image = _peImage; if (image != null) { image.Dispose(); _peImage = null; } var imageBlock = _lazyImageBlock; if (imageBlock != null) { imageBlock.Dispose(); _lazyImageBlock = null; } var metadataBlock = _lazyMetadataBlock; if (metadataBlock != null) { metadataBlock.Dispose(); _lazyMetadataBlock = null; } var peSectionBlocks = _lazyPESectionBlocks; if (peSectionBlocks != null) { foreach (var block in peSectionBlocks) { if (block != null) { block.Dispose(); } } _lazyPESectionBlocks = null; } }