Ejemplo n.º 1
0
        /// <summary>
        /// Relocate the contents of the metadata blob, which contains two tables with embedded RVAs.
        /// </summary>
        public void RelocateMetadataBlob(Stream outputStream)
        {
            long initialStreamLength = outputStream.Length;

            outputStream.Position = 0;

            // The output is already a valid PE file so use that to access the output metadata blob
            PEReader peReader = new PEReader(outputStream);

            // Create a patched up metadata blob whose RVAs are correct w.r.t the output image
            BlobBuilder relocatedMetadataBlob = MetadataRvaFixupBuilder.Relocate(peReader, RelocateRVA);

            Debug.Assert(_metadataFileOffset > 0);
            outputStream.Position = _metadataFileOffset;

            // Splice the new metadata blob back into the output stream
            relocatedMetadataBlob.WriteContentTo(outputStream);
            Debug.Assert(initialStreamLength == outputStream.Length);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Output the section with a given name. For sections existent in the source MSIL PE file
        /// (.text, optionally .rsrc and .reloc), we first copy the content of the input MSIL PE file
        /// and then call the section serialization callback to emit the extra content after the input
        /// section content.
        /// </summary>
        /// <param name="name">Section name</param>
        /// <param name="location">RVA and file location where the section will be put</param>
        /// <returns>Blob builder representing the section data</returns>
        protected override BlobBuilder SerializeSection(string name, SectionLocation location)
        {
            BlobBuilder sectionDataBuilder = null;
            bool        haveCustomSection  = _customSections.Contains(name);
            int         sectionIndex       = _peReader.PEHeaders.SectionHeaders.Count() - 1;
            int         sectionStartRva    = location.RelativeVirtualAddress;

            while (sectionIndex >= 0 && _peReader.PEHeaders.SectionHeaders[sectionIndex].Name != name)
            {
                sectionIndex--;
            }
            if (sectionIndex >= 0)
            {
                SectionHeader sectionHeader = _peReader.PEHeaders.SectionHeaders[sectionIndex];
                int           sectionOffset = (_peReader.IsLoadedImage ? sectionHeader.VirtualAddress : sectionHeader.PointerToRawData);
                int           rvaDelta      = location.RelativeVirtualAddress - sectionHeader.VirtualAddress;

                _sectionRvaDeltas.Add(new SectionRVADelta(
                                          startRVA: sectionHeader.VirtualAddress,
                                          endRVA: sectionHeader.VirtualAddress + Math.Max(sectionHeader.VirtualSize, sectionHeader.SizeOfRawData),
                                          deltaRVA: rvaDelta));

                unsafe
                {
                    int        bytesToRead        = Math.Min(sectionHeader.SizeOfRawData, sectionHeader.VirtualSize);
                    BlobReader inputSectionReader = _peReader.GetEntireImage().GetReader(sectionOffset, bytesToRead);

                    if (name == ".rsrc")
                    {
                        // There seems to be a bug in BlobBuilder - when we LinkSuffix to an empty blob builder,
                        // the blob data goes out of sync and WriteContentTo outputs garbage.
                        sectionDataBuilder = PEResourceHelper.Relocate(inputSectionReader, rvaDelta);
                    }
                    else if (name == ".text")
                    {
                        int inputMetadataRva        = _peReader.PEHeaders.CorHeader.MetadataDirectory.RelativeVirtualAddress;
                        int inputMetadataSectionRva = sectionHeader.VirtualAddress;

                        // The metadata is in .text always ... right?
                        Debug.Assert(inputMetadataRva >= sectionHeader.VirtualAddress && inputMetadataRva < (sectionHeader.VirtualAddress + sectionHeader.VirtualSize));

                        sectionDataBuilder = new BlobBuilder();

                        // Write section contents up to the start of metadata
                        sectionDataBuilder.WriteBytes(inputSectionReader.CurrentPointer, inputMetadataRva - sectionHeader.VirtualAddress);

                        // Fix-up RVAs in the metadata stream
                        MetadataRvaFixupBuilder.Relocate(_peReader, rvaDelta).WriteContentTo(sectionDataBuilder);

                        // Write the rest of the section after the metadata
                        inputSectionReader.Offset = inputMetadataRva + _peReader.PEHeaders.MetadataSize - sectionHeader.VirtualAddress;
                        sectionDataBuilder.WriteBytes(inputSectionReader.CurrentPointer, bytesToRead - inputSectionReader.Offset);

                        Debug.Assert(sectionDataBuilder.Count == inputSectionReader.Length);
                    }
                    else
                    {
                        sectionDataBuilder = new BlobBuilder();
                        sectionDataBuilder.WriteBytes(inputSectionReader.CurrentPointer, inputSectionReader.RemainingBytes);
                    }

                    int corHeaderRvaDelta = _peReader.PEHeaders.PEHeader.CorHeaderTableDirectory.RelativeVirtualAddress - sectionHeader.VirtualAddress;
                    if (corHeaderRvaDelta >= 0 && corHeaderRvaDelta < bytesToRead)
                    {
                        // Assume COR header resides in this section, deserialize it and store its location
                        _corHeaderFileOffset      = location.PointerToRawData + corHeaderRvaDelta;
                        inputSectionReader.Offset = corHeaderRvaDelta;
                        _corHeaderBuilder         = new CorHeaderBuilder(ref inputSectionReader);
                    }

                    int alignedSize = sectionHeader.VirtualSize;

                    // When custom section data is present, align the section size to 4K to prevent
                    // pre-generated MSIL relocations from tampering with native relocations.
                    if (_customSections.Contains(name))
                    {
                        alignedSize = (alignedSize + 0xFFF) & ~0xFFF;
                    }

                    if (alignedSize > bytesToRead)
                    {
                        // If the number of bytes read from the source PE file is less than the virtual size,
                        // zero pad to the end of virtual size before emitting extra section data
                        sectionDataBuilder.WriteBytes(0, alignedSize - bytesToRead);
                    }
                    location = new SectionLocation(
                        location.RelativeVirtualAddress + sectionDataBuilder.Count,
                        location.PointerToRawData + sectionDataBuilder.Count);
                }
            }

            if (_sectionSerializer != null)
            {
                BlobBuilder extraData = _sectionSerializer(name, location, sectionStartRva);
                if (extraData != null)
                {
                    if (sectionDataBuilder == null)
                    {
                        // See above - there's a bug due to which LinkSuffix to an empty BlobBuilder screws up the blob content.
                        sectionDataBuilder = extraData;
                    }
                    else
                    {
                        sectionDataBuilder.LinkSuffix(extraData);
                    }
                }
            }

            // Make sure the section has at least 1 byte, otherwise the PE emitter goes mad,
            // messes up the section map and corrups the output executable.
            if (sectionDataBuilder == null)
            {
                sectionDataBuilder = new BlobBuilder();
            }

            if (sectionDataBuilder.Count == 0)
            {
                sectionDataBuilder.WriteByte(0);
            }

            return(sectionDataBuilder);
        }