/// <summary> /// Looks like this function reads beginning of the header described in /// ECMA-335 24.2.1 Metadata root /// </summary> private void ReadMetadataHeader(ref BlobReader memReader, out string versionString) { if (memReader.RemainingBytes < COR20Constants.MinimumSizeofMetadataHeader) { throw new BadImageFormatException("MetadataHeaderTooSmall"); } uint signature = memReader.ReadUInt32(); if (signature != COR20Constants.COR20MetadataSignature) { throw new BadImageFormatException("MetadataSignature"); } // major version memReader.ReadUInt16(); // minor version memReader.ReadUInt16(); // reserved: memReader.ReadUInt32(); int versionStringSize = memReader.ReadInt32(); if (memReader.RemainingBytes < versionStringSize) { throw new BadImageFormatException("NotEnoughSpaceForVersionString"); } int numberOfBytesRead; versionString = memReader.GetMemoryBlockAt(0, versionStringSize).PeekUtf8NullTerminated(0, out numberOfBytesRead); memReader.Offset += versionStringSize; }
public unsafe MetadataReader(byte *metadata, int length, MetadataReaderOptions options) { // Do not throw here when length is 0. We'll throw BadImageFormatException later on, so that the caller doesn't need to // worry about the image (stream) being empty and can handle all image errors by catching BadImageFormatException. if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } this.Block = new MemoryBlock(metadata, length); _options = options; var headerReader = new BlobReader(this.Block); this.ReadMetadataHeader(ref headerReader, out _versionString); _metadataKind = GetMetadataKind(_versionString); var streamHeaders = this.ReadStreamHeaders(ref headerReader); // storage header and stream headers: MemoryBlock metadataTableStream; MemoryBlock standalonePdbStream; this.InitializeStreamReaders(ref this.Block, streamHeaders, out _metadataStreamKind, out metadataTableStream, out standalonePdbStream); int[] externalTableRowCountsOpt; if (standalonePdbStream.Length > 0) { ReadStandalonePortablePdbStream(standalonePdbStream, out _debugMetadataHeader, out externalTableRowCountsOpt); } else { externalTableRowCountsOpt = null; } var tableReader = new BlobReader(metadataTableStream); HeapSizes heapSizes; int[] metadataTableRowCounts; this.ReadMetadataTableHeader(ref tableReader, out heapSizes, out metadataTableRowCounts, out _sortedTables); this.InitializeTableReaders(tableReader.GetMemoryBlockAt(0, tableReader.RemainingBytes), heapSizes, metadataTableRowCounts, externalTableRowCountsOpt); }
public static MethodBodyBlock Create(BlobReader reader) { int startOffset = reader.Offset; int ilSize; // Error need to check if the Memory Block is empty. This is false for all the calls... byte headByte = reader.ReadByte(); if ((headByte & ILFormatMask) == ILTinyFormat) { // tiny IL can't have locals so technically this shouldn't matter, // but false is consistent with other metadata readers and helps // for use cases involving comparing our output with theirs. const bool initLocalsForTinyIL = false; ilSize = headByte >> ILTinyFormatSizeShift; return(new MethodBodyBlock( initLocalsForTinyIL, 8, default(StandaloneSignatureHandle), reader.GetMemoryBlockAt(0, ilSize), ImmutableArray <ExceptionRegion> .Empty, 1 + ilSize // header + IL )); } if ((headByte & ILFormatMask) != ILFatFormat) { throw new BadImageFormatException(SR.Format(SR.InvalidMethodHeader1, headByte)); } // FatILFormat byte headByte2 = reader.ReadByte(); if ((headByte2 >> ILFatFormatHeaderSizeShift) != ILFatFormatHeaderSize) { throw new BadImageFormatException(SR.Format(SR.InvalidMethodHeader2, headByte, headByte2)); } bool localsInitialized = (headByte & ILInitLocals) == ILInitLocals; bool hasExceptionHandlers = (headByte & ILMoreSects) == ILMoreSects; ushort maxStack = reader.ReadUInt16(); ilSize = reader.ReadInt32(); int localSignatureToken = reader.ReadInt32(); StandaloneSignatureHandle localSignatureHandle; if (localSignatureToken == 0) { localSignatureHandle = default(StandaloneSignatureHandle); } else if ((localSignatureToken & TokenTypeIds.TypeMask) == TokenTypeIds.Signature) { localSignatureHandle = StandaloneSignatureHandle.FromRowId((int)((uint)localSignatureToken & TokenTypeIds.RIDMask)); } else { throw new BadImageFormatException(SR.Format(SR.InvalidLocalSignatureToken, unchecked ((uint)localSignatureToken))); } var ilBlock = reader.GetMemoryBlockAt(0, ilSize); reader.Offset += ilSize; ImmutableArray <ExceptionRegion> exceptionHandlers; if (hasExceptionHandlers) { reader.Align(4); byte sehHeader = reader.ReadByte(); if ((sehHeader & SectEHTable) != SectEHTable) { throw new BadImageFormatException(SR.Format(SR.InvalidSehHeader, sehHeader)); } bool sehFatFormat = (sehHeader & SectFatFormat) == SectFatFormat; int dataSize = reader.ReadByte(); if (sehFatFormat) { dataSize += reader.ReadUInt16() << 8; exceptionHandlers = ReadFatExceptionHandlers(ref reader, dataSize / 24); } else { reader.Offset += 2; // skip over reserved field exceptionHandlers = ReadSmallExceptionHandlers(ref reader, dataSize / 12); } } else { exceptionHandlers = ImmutableArray <ExceptionRegion> .Empty; } return(new MethodBodyBlock( localsInitialized, maxStack, localSignatureHandle, ilBlock, exceptionHandlers, reader.Offset - startOffset)); }
/// <summary> /// Creates a metadata reader from the metadata stored at the given memory location. /// </summary> /// <remarks> /// The memory is owned by the caller and it must be kept memory alive and unmodified throughout the lifetime of the <see cref="MetadataReader"/>. /// Use <see cref="PEReaderExtensions.GetMetadataReader(PortableExecutable.PEReader, MetadataReaderOptions, MetadataStringDecoder)"/> to obtain /// metadata from a PE image. /// </remarks> public unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder) { if (length <= 0) { throw new ArgumentOutOfRangeException("length"); } if (metadata == null) { throw new ArgumentNullException("metadata"); } if (utf8Decoder == null) { utf8Decoder = MetadataStringDecoder.DefaultUTF8; } if (!(utf8Decoder.Encoding is UTF8Encoding)) { throw new ArgumentException(MetadataResources.MetadataStringDecoderEncodingMustBeUtf8, "utf8Decoder"); } if (!BitConverter.IsLittleEndian) { throw new PlatformNotSupportedException(MetadataResources.LitteEndianArchitectureRequired); } this.Block = new MemoryBlock(metadata, length); this.options = options; this.utf8Decoder = utf8Decoder; BlobReader memReader = new BlobReader(this.Block); this.ReadMetadataHeader(ref memReader); // storage header and stream headers: MemoryBlock metadataTableStream; var streamHeaders = this.ReadStreamHeaders(ref memReader); this.InitializeStreamReaders(ref this.Block, streamHeaders, out metadataTableStream); memReader = new BlobReader(metadataTableStream); uint[] metadataTableRowCounts; this.ReadMetadataTableHeader(ref memReader, out metadataTableRowCounts); this.InitializeTableReaders(memReader.GetMemoryBlockAt(0, memReader.RemainingBytes), metadataTableRowCounts); // This previously could occur in obfuscated assemblies but a check was added to prevent // it getting to this point Debug.Assert(this.AssemblyTable.NumberOfRows <= 1); // Although the specification states that the module table will have exactly one row, // the native metadata reader would successfully read files containing more than one row. // Such files exist in the wild and may be produced by obfuscators. if (this.ModuleTable.NumberOfRows < 1) { throw new BadImageFormatException(string.Format(MetadataResources.ModuleTableInvalidNumberOfRows, this.ModuleTable.NumberOfRows)); } // read this.namespaceCache = new NamespaceCache(this); if (this.metadataKind != MetadataKind.Ecma335) { this.WinMDMscorlibRef = FindMscorlibAssemblyRefNoProjection(); } }
/// <summary> /// Looks like this function reads beginning of the header described in /// Ecma-335 24.2.1 Metadata root /// </summary> private void ReadMetadataHeader(ref BlobReader memReader) { if (memReader.RemainingBytes < COR20Constants.MinimumSizeofMetadataHeader) { throw new BadImageFormatException(MetadataResources.MetadataHeaderTooSmall); } this.metadataHeader.Signature = memReader.ReadUInt32(); if (this.metadataHeader.Signature != COR20Constants.COR20MetadataSignature) { throw new BadImageFormatException(MetadataResources.MetadataSignature); } this.metadataHeader.MajorVersion = memReader.ReadUInt16(); this.metadataHeader.MinorVersion = memReader.ReadUInt16(); this.metadataHeader.ExtraData = memReader.ReadUInt32(); this.metadataHeader.VersionStringSize = memReader.ReadInt32(); if (memReader.RemainingBytes < this.metadataHeader.VersionStringSize) { throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForVersionString); } int numberOfBytesRead; this.metadataHeader.VersionString = memReader.GetMemoryBlockAt(0, this.metadataHeader.VersionStringSize).PeekUtf8NullTerminated(0, null, utf8Decoder, out numberOfBytesRead, '\0'); memReader.SkipBytes(this.metadataHeader.VersionStringSize); this.metadataKind = GetMetadataKind(metadataHeader.VersionString); }
/// <summary> /// Creates a metadata reader from the metadata stored at the given memory location. /// </summary> /// <remarks> /// The memory is owned by the caller and it must be kept memory alive and unmodified throughout the lifetime of the <see cref="MetadataReader"/>. /// Use <see cref="PEReaderExtensions.GetMetadataReader(PortableExecutable.PEReader, MetadataReaderOptions, MetadataStringDecoder)"/> to obtain /// metadata from a PE image. /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is not positive.</exception> /// <exception cref="ArgumentNullException"><paramref name="metadata"/> is null.</exception> /// <exception cref="ArgumentException">The encoding of <paramref name="utf8Decoder"/> is not <see cref="UTF8Encoding"/>.</exception> /// <exception cref="PlatformNotSupportedException">The current platform is big-endian.</exception> public unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder) { // Do not throw here when length is 0. We'll throw BadImageFormatException later on, so that the caller doesn't need to // worry about the image (stream) being empty and can handle all image errors by catching BadImageFormatException. if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (utf8Decoder == null) { utf8Decoder = MetadataStringDecoder.DefaultUTF8; } if (!(utf8Decoder.Encoding is UTF8Encoding)) { throw new ArgumentException(SR.MetadataStringDecoderEncodingMustBeUtf8, nameof(utf8Decoder)); } if (!BitConverter.IsLittleEndian) { Throw.LitteEndianArchitectureRequired(); } this.Block = new MemoryBlock(metadata, length); _options = options; this.UTF8Decoder = utf8Decoder; var headerReader = new BlobReader(this.Block); this.ReadMetadataHeader(ref headerReader, out _versionString); _metadataKind = GetMetadataKind(_versionString); var streamHeaders = this.ReadStreamHeaders(ref headerReader); // storage header and stream headers: MemoryBlock metadataTableStream; MemoryBlock standalonePdbStream; this.InitializeStreamReaders(ref this.Block, streamHeaders, out _metadataStreamKind, out metadataTableStream, out standalonePdbStream); int[] externalTableRowCountsOpt; if (standalonePdbStream.Length > 0) { ReadStandalonePortablePdbStream(standalonePdbStream, out _debugMetadataHeader, out externalTableRowCountsOpt); } else { externalTableRowCountsOpt = null; } var tableReader = new BlobReader(metadataTableStream); HeapSizes heapSizes; int[] metadataTableRowCounts; this.ReadMetadataTableHeader(ref tableReader, out heapSizes, out metadataTableRowCounts, out _sortedTables); this.InitializeTableReaders(tableReader.GetMemoryBlockAt(0, tableReader.RemainingBytes), heapSizes, metadataTableRowCounts, externalTableRowCountsOpt); // This previously could occur in obfuscated assemblies but a check was added to prevent // it getting to this point Debug.Assert(this.AssemblyTable.NumberOfRows <= 1); // Although the specification states that the module table will have exactly one row, // the native metadata reader would successfully read files containing more than one row. // Such files exist in the wild and may be produced by obfuscators. if (standalonePdbStream.Length == 0 && this.ModuleTable.NumberOfRows < 1) { throw new BadImageFormatException(SR.Format(SR.ModuleTableInvalidNumberOfRows, this.ModuleTable.NumberOfRows)); } // read this.NamespaceCache = new NamespaceCache(this); if (_metadataKind != MetadataKind.Ecma335) { this.WinMDMscorlibRef = FindMscorlibAssemblyRefNoProjection(); } }
/// <summary> /// Looks like this function reads beginning of the header described in /// ECMA-335 24.2.1 Metadata root /// </summary> private void ReadMetadataHeader(ref BlobReader memReader, out string versionString) { if (memReader.RemainingBytes < COR20Constants.MinimumSizeofMetadataHeader) { throw new BadImageFormatException(SR.MetadataHeaderTooSmall); } uint signature = memReader.ReadUInt32(); if (signature != COR20Constants.COR20MetadataSignature) { throw new BadImageFormatException(SR.MetadataSignature); } // major version memReader.ReadUInt16(); // minor version memReader.ReadUInt16(); // reserved: memReader.ReadUInt32(); int versionStringSize = memReader.ReadInt32(); if (memReader.RemainingBytes < versionStringSize) { throw new BadImageFormatException(SR.NotEnoughSpaceForVersionString); } int numberOfBytesRead; versionString = memReader.GetMemoryBlockAt(0, versionStringSize).PeekUtf8NullTerminated(0, null, UTF8Decoder, out numberOfBytesRead, '\0'); memReader.SkipBytes(versionStringSize); }
public static MethodBodyBlock Create(BlobReader reader) { int startOffset = reader.Offset; int ilSize; // Error need to check if the Memory Block is empty. This is calse for all the calls... byte headByte = reader.ReadByte(); if ((headByte & ILFormatMask) == ILTinyFormat) { // tiny IL can't have locals so technically this shouldn't matter, // but false is consistent with other metadata readers and helps // for use cases involving comparing our output with theirs. const bool initLocalsForTinyIL = false; ilSize = headByte >> ILTinyFormatSizeShift; return new MethodBodyBlock( initLocalsForTinyIL, 8, default(StandaloneSignatureHandle), reader.GetMemoryBlockAt(0, ilSize), ImmutableArray<ExceptionRegion>.Empty, 1 + ilSize // header + IL ); } if ((headByte & ILFormatMask) != ILFatFormat) { throw new BadImageFormatException(string.Format(MetadataResources.InvalidMethodHeader1, headByte)); } // FatILFormat byte headByte2 = reader.ReadByte(); if ((headByte2 >> ILFatFormatHeaderSizeShift) != ILFatFormatHeaderSize) { throw new BadImageFormatException(string.Format(MetadataResources.InvalidMethodHeader2, headByte, headByte2)); } bool localsInitialized = (headByte & ILInitLocals) == ILInitLocals; bool hasExceptionHandlers = (headByte & ILMoreSects) == ILMoreSects; ushort maxStack = reader.ReadUInt16(); ilSize = reader.ReadInt32(); int localSignatureToken = reader.ReadInt32(); StandaloneSignatureHandle localSignatureHandle; if (localSignatureToken == 0) { localSignatureHandle = default(StandaloneSignatureHandle); } else if ((localSignatureToken & TokenTypeIds.TokenTypeMask) == TokenTypeIds.Signature) { localSignatureHandle = StandaloneSignatureHandle.FromRowId((uint)localSignatureToken & TokenTypeIds.RIDMask); } else { throw new BadImageFormatException(string.Format(MetadataResources.InvalidLocalSignatureToken, unchecked((uint)localSignatureToken))); } var ilBlock = reader.GetMemoryBlockAt(0, ilSize); reader.SkipBytes(ilSize); ImmutableArray<ExceptionRegion> exceptionHandlers; if (hasExceptionHandlers) { reader.Align(4); byte sehHeader = reader.ReadByte(); if ((sehHeader & SectEHTable) != SectEHTable) { throw new BadImageFormatException(string.Format(MetadataResources.InvalidSehHeader, sehHeader)); } bool sehFatFormat = (sehHeader & SectFatFormat) == SectFatFormat; int dataSize = reader.ReadByte(); if (sehFatFormat) { dataSize += reader.ReadUInt16() << 8; exceptionHandlers = ReadFatExceptionHandlers(ref reader, dataSize / 24); } else { reader.SkipBytes(2); // skip over reserved field exceptionHandlers = ReadSmallExceptionHandlers(ref reader, dataSize / 12); } } else { exceptionHandlers = ImmutableArray<ExceptionRegion>.Empty; } return new MethodBodyBlock( localsInitialized, maxStack, localSignatureHandle, ilBlock, exceptionHandlers, reader.Offset - startOffset); }