Esempio n. 1
0
        /// <summary>
        /// Gets metadata about CLI Assembly in Microsoft PE format.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="fields">The optional fields of the <see cref="AssemblyMetadata" /> structure to populate.</param>
        /// <returns>The metadata or null if the stream does not represent a CLI assembly.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="stream"/> is null.</exception>
        public static AssemblyMetadata GetAssemblyMetadata(Stream stream, AssemblyMetadataFields fields)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            return(AssemblyMetadata.ReadAssemblyMetadata(stream, fields));
        }
Esempio n. 2
0
        /// <summary>
        /// Gets the Major and Minor components of the CLI runtime version of a CLI Assembly in Microsoft PE format.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="fields">The optional fields of the <see cref="AssemblyMetadata" /> structure to populate.</param>
        /// <returns>The version, of which only the major and minor components are populated,
        /// or null if the stream does not represent a CLI assembly.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="filePath"/> is null.</exception>
        public static AssemblyMetadata GetAssemblyMetadata(string filePath, AssemblyMetadataFields fields)
        {
            if (filePath == null)
            {
                throw new ArgumentNullException("filePath");
            }

            if (!File.Exists(filePath))
            {
                return(null);
            }

            using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                return(AssemblyMetadata.ReadAssemblyMetadata(stream, fields));
            }
        }
Esempio n. 3
0
        internal static AssemblyMetadata ReadAssemblyMetadata(Stream stream, AssemblyMetadataFields fields)
        {
            long length = stream.Length;

            if (length < 0x40)
            {
                return(null);
            }

            BinaryReader reader = new BinaryReader(stream);

            // Read the pointer to the PE header.
            stream.Position = 0x3c;
            uint peHeaderPtr = reader.ReadUInt32();

            if (peHeaderPtr == 0)
            {
                peHeaderPtr = 0x80;
            }

            // Ensure there is at least enough room for the following structures:
            //     24 byte PE Signature & Header
            //     28 byte Standard Fields         (24 bytes for PE32+)
            //     68 byte NT Fields               (88 bytes for PE32+)
            // >= 128 byte Data Dictionary Table
            if (peHeaderPtr > length - 256)
            {
                return(null);
            }

            // Check the PE signature.  Should equal 'PE\0\0'.
            stream.Position = peHeaderPtr;
            uint peSignature = reader.ReadUInt32();

            if (peSignature != 0x00004550)
            {
                return(null);
            }

            // Read PE header fields.
            ushort machine            = reader.ReadUInt16();
            ushort numberOfSections   = reader.ReadUInt16();
            uint   timeStamp          = reader.ReadUInt32();
            uint   symbolTablePtr     = reader.ReadUInt32();
            uint   numberOfSymbols    = reader.ReadUInt32();
            ushort optionalHeaderSize = reader.ReadUInt16();
            ushort characteristics    = reader.ReadUInt16();

            // Read PE magic number from Standard Fields to determine format.
            PEFormat peFormat = (PEFormat)reader.ReadUInt16();

            if (peFormat != PEFormat.PE32 && peFormat != PEFormat.PE32Plus)
            {
                return(null);
            }

            // Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
            // When this is non-zero then the file contains CLI data otherwise not.
            stream.Position = peHeaderPtr + (peFormat == PEFormat.PE32 ? 232 : 248);
            uint cliHeaderRva = reader.ReadUInt32();

            if (cliHeaderRva == 0)
            {
                return(null);
            }

            // Read section headers.  Each one is 40 bytes.
            //    8 byte Name
            //    4 byte Virtual Size
            //    4 byte Virtual Address
            //    4 byte Data Size
            //    4 byte Data Pointer
            //  ... total of 40 bytes
            uint sectionTablePtr = peHeaderPtr + 24 + optionalHeaderSize;

            Section[] sections = new Section[numberOfSections];
            for (int i = 0; i < numberOfSections; i++)
            {
                stream.Position = sectionTablePtr + i * 40 + 8;

                Section section = new Section();
                section.VirtualSize    = reader.ReadUInt32();
                section.VirtualAddress = reader.ReadUInt32();
                reader.ReadUInt32();
                section.Pointer = reader.ReadUInt32();

                sections[i] = section;
            }

            // Read parts of the CLI header.
            uint cliHeaderPtr = ResolveRva(sections, cliHeaderRva);

            if (cliHeaderPtr == 0)
            {
                return(null);
            }

            stream.Position = cliHeaderPtr + 4;
            ushort   majorRuntimeVersion = reader.ReadUInt16();
            ushort   minorRuntimeVersion = reader.ReadUInt16();
            uint     metadataRva         = reader.ReadUInt32();
            uint     metadataSize        = reader.ReadUInt32();
            CorFlags corflags            = (CorFlags)reader.ReadUInt32();

            // Read optional fields.
            AssemblyName         assemblyName       = null;
            IList <AssemblyName> assemblyReferences = null;
            string runtimeVersion = null;

            if ((fields & AssemblyMetadataFields.RuntimeVersion) != 0)
            {
                uint metadataPtr = ResolveRva(sections, metadataRva);
                stream.Position = metadataPtr + 12;

                int    paddedRuntimeVersionLength = reader.ReadInt32();
                byte[] runtimeVersionBytes        = reader.ReadBytes(paddedRuntimeVersionLength);

                int runtimeVersionLength = 0;
                while (runtimeVersionLength < paddedRuntimeVersionLength &&
                       runtimeVersionBytes[runtimeVersionLength] != 0)
                {
                    runtimeVersionLength += 1;
                }

                runtimeVersion = Encoding.UTF8.GetString(runtimeVersionBytes, 0, runtimeVersionLength);
            }

            if ((fields & (AssemblyMetadataFields.AssemblyName | AssemblyMetadataFields.AssemblyReferences)) != 0)
            {
                // Using Cecil.
                stream.Position = 0;
                var imageReader = new ImageReader(stream);

                if ((fields & AssemblyMetadataFields.AssemblyName) != 0)
                {
                    assemblyName = imageReader.GetAssemblyName();
                }

                if ((fields & AssemblyMetadataFields.AssemblyReferences) != 0)
                {
                    assemblyReferences = imageReader.GetAssemblyReferences();
                }
            }

            // Done.
            return(new AssemblyMetadata(majorRuntimeVersion, minorRuntimeVersion, corflags, peFormat,
                                        assemblyName, assemblyReferences, runtimeVersion));
        }
Esempio n. 4
0
        /// <summary>
        /// Gets metadata about CLI Assembly in Microsoft PE format.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="fields">The optional fields of the <see cref="AssemblyMetadata" /> structure to populate.</param>
        /// <returns>The metadata or null if the stream does not represent a CLI assembly.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="stream"/> is null.</exception>
        public static AssemblyMetadata GetAssemblyMetadata(Stream stream, AssemblyMetadataFields fields)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            return AssemblyMetadata.ReadAssemblyMetadata(stream, fields);
        }
Esempio n. 5
0
        /// <summary>
        /// Gets the Major and Minor components of the CLI runtime version of a CLI Assembly in Microsoft PE format.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="fields">The optional fields of the <see cref="AssemblyMetadata" /> structure to populate.</param>
        /// <returns>The version, of which only the major and minor components are populated,
        /// or null if the stream does not represent a CLI assembly.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="filePath"/> is null.</exception>
        public static AssemblyMetadata GetAssemblyMetadata(string filePath, AssemblyMetadataFields fields)
        {
            if (filePath == null)
                throw new ArgumentNullException("filePath");

            if (!File.Exists(filePath))
                return null;

            using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                return AssemblyMetadata.ReadAssemblyMetadata(stream, fields);
            }
        }
Esempio n. 6
0
        internal static AssemblyMetadata ReadAssemblyMetadata(Stream stream, AssemblyMetadataFields fields)
        {
            long length = stream.Length;
            if (length < 0x40)
                return null;

            BinaryReader reader = new BinaryReader(stream);

            // Read the pointer to the PE header.
            stream.Position = 0x3c;
            uint peHeaderPtr = reader.ReadUInt32();
            if (peHeaderPtr == 0)
                peHeaderPtr = 0x80;

            // Ensure there is at least enough room for the following structures:
            //     24 byte PE Signature & Header
            //     28 byte Standard Fields         (24 bytes for PE32+)
            //     68 byte NT Fields               (88 bytes for PE32+)
            // >= 128 byte Data Dictionary Table
            if (peHeaderPtr > length - 256)
                return null;

            // Check the PE signature.  Should equal 'PE\0\0'.
            stream.Position = peHeaderPtr;
            uint peSignature = reader.ReadUInt32();
            if (peSignature != 0x00004550)
                return null;

            // Read PE header fields.
            ushort machine = reader.ReadUInt16();
            ushort numberOfSections = reader.ReadUInt16();
            uint timeStamp = reader.ReadUInt32();
            uint symbolTablePtr = reader.ReadUInt32();
            uint numberOfSymbols = reader.ReadUInt32();
            ushort optionalHeaderSize = reader.ReadUInt16();
            ushort characteristics = reader.ReadUInt16();

            // Read PE magic number from Standard Fields to determine format.
            PEFormat peFormat = (PEFormat)reader.ReadUInt16();
            if (peFormat != PEFormat.PE32 && peFormat != PEFormat.PE32Plus)
                return null;

            // Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
            // When this is non-zero then the file contains CLI data otherwise not.
            stream.Position = peHeaderPtr + (peFormat == PEFormat.PE32 ? 232 : 248);
            uint cliHeaderRva = reader.ReadUInt32();
            if (cliHeaderRva == 0)
                return null;

            // Read section headers.  Each one is 40 bytes.
            //    8 byte Name
            //    4 byte Virtual Size
            //    4 byte Virtual Address
            //    4 byte Data Size
            //    4 byte Data Pointer
            //  ... total of 40 bytes
            uint sectionTablePtr = peHeaderPtr + 24 + optionalHeaderSize;
            Section[] sections = new Section[numberOfSections];
            for (int i = 0; i < numberOfSections; i++)
            {
                stream.Position = sectionTablePtr + i * 40 + 8;

                Section section = new Section();
                section.VirtualSize = reader.ReadUInt32();
                section.VirtualAddress = reader.ReadUInt32();
                reader.ReadUInt32();
                section.Pointer = reader.ReadUInt32();

                sections[i] = section;
            }

            // Read parts of the CLI header.
            uint cliHeaderPtr = ResolveRva(sections, cliHeaderRva);
            if (cliHeaderPtr == 0)
                return null;

            stream.Position = cliHeaderPtr + 4;
            ushort majorRuntimeVersion = reader.ReadUInt16();
            ushort minorRuntimeVersion = reader.ReadUInt16();
            uint metadataRva = reader.ReadUInt32();
            uint metadataSize = reader.ReadUInt32();
            CorFlags corflags = (CorFlags)reader.ReadUInt32();

            // Read optional fields.
            AssemblyName assemblyName = null;
            IList<AssemblyName> assemblyReferences = null;
            string runtimeVersion = null;

            if ((fields & AssemblyMetadataFields.RuntimeVersion) != 0)
            {
                uint metadataPtr = ResolveRva(sections, metadataRva);
                stream.Position = metadataPtr + 12;

                int paddedRuntimeVersionLength = reader.ReadInt32();
                byte[] runtimeVersionBytes = reader.ReadBytes(paddedRuntimeVersionLength);

                int runtimeVersionLength = 0;
                while (runtimeVersionLength < paddedRuntimeVersionLength
                    && runtimeVersionBytes[runtimeVersionLength] != 0)
                    runtimeVersionLength += 1;

                runtimeVersion = Encoding.UTF8.GetString(runtimeVersionBytes, 0, runtimeVersionLength);
            }

            if ((fields & (AssemblyMetadataFields.AssemblyName | AssemblyMetadataFields.AssemblyReferences)) != 0)
            {
                // Using Cecil.
                stream.Position = 0;
                var imageReader = new ImageReader(stream);

                if ((fields & AssemblyMetadataFields.AssemblyName) != 0)
                    assemblyName = imageReader.GetAssemblyName();

                if ((fields & AssemblyMetadataFields.AssemblyReferences) != 0)
                    assemblyReferences = imageReader.GetAssemblyReferences();
            }

            // Done.
            return new AssemblyMetadata(majorRuntimeVersion, minorRuntimeVersion, corflags, peFormat,
                assemblyName, assemblyReferences, runtimeVersion);
        }