Пример #1
0
        /// <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;
        }
Пример #2
0
        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);
        }
Пример #3
0
        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));
        }
Пример #4
0
        /// <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();
            }
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        /// <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();
            }
        }
Пример #7
0
        /// <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);
        }
Пример #8
0
        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);
        }