示例#1
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));
        }