Ejemplo n.º 1
0
        /// <summary>
        /// Emit built sections into the R2R PE file.
        /// </summary>
        /// <param name="outputStream">Output stream for the final R2R PE file</param>
        public void Write(Stream outputStream)
        {
            BlobBuilder outputPeFile = new BlobBuilder();

            Serialize(outputPeFile);

            CorHeaderBuilder corHeader = CorHeader;

            if (corHeader != null)
            {
                corHeader.Flags = (CorHeader.Flags & ~CorFlags.ILOnly) | CorFlags.ILLibrary;

                corHeader.MetadataDirectory                = RelocateDirectoryEntry(corHeader.MetadataDirectory);
                corHeader.ResourcesDirectory               = RelocateDirectoryEntry(corHeader.ResourcesDirectory);
                corHeader.StrongNameSignatureDirectory     = RelocateDirectoryEntry(corHeader.StrongNameSignatureDirectory);
                corHeader.CodeManagerTableDirectory        = RelocateDirectoryEntry(corHeader.CodeManagerTableDirectory);
                corHeader.VtableFixupsDirectory            = RelocateDirectoryEntry(corHeader.VtableFixupsDirectory);
                corHeader.ExportAddressTableJumpsDirectory = RelocateDirectoryEntry(corHeader.ExportAddressTableJumpsDirectory);
                corHeader.ManagedNativeHeaderDirectory     = RelocateDirectoryEntry(corHeader.ManagedNativeHeaderDirectory);

                _sectionBuilder.UpdateCorHeader(corHeader);
            }

            _sectionBuilder.RelocateOutputFile(
                outputPeFile,
                _peReader.PEHeaders.PEHeader.ImageBase,
                corHeader,
                CorHeaderFileOffset,
                outputStream);

            RelocateMetadataBlob(outputStream);

            _written = true;
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Update the COR header.
 /// </summary>
 /// <param name="corHeader">COR header builder to update</param>
 public void UpdateCorHeader(CorHeaderBuilder corHeader)
 {
     if (_readyToRunHeaderSymbol != null)
     {
         SymbolTarget headerTarget  = _symbolMap[_readyToRunHeaderSymbol];
         Section      headerSection = _sections[headerTarget.SectionIndex];
         Debug.Assert(headerSection.RVAWhenPlaced != 0);
         int r2rHeaderRVA = headerSection.RVAWhenPlaced + headerTarget.Offset;
         corHeader.ManagedNativeHeaderDirectory = new DirectoryEntry(r2rHeaderRVA, _readyToRunHeaderSize);
     }
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Relocate the produced PE file and output the result into a given stream.
        /// </summary>
        /// <param name="peFile">Blob builder representing the complete PE file</param>
        /// <param name="defaultImageBase">Default load address for the image</param>
        /// <param name="corHeaderBuilder">COR header</param>
        /// <param name="corHeaderFileOffset">File position of the COR header</param>
        /// <param name="outputStream">Stream to receive the relocated PE file</param>
        public void RelocateOutputFile(
            BlobBuilder peFile,
            ulong defaultImageBase,
            CorHeaderBuilder corHeaderBuilder,
            int corHeaderFileOffset,
            Stream outputStream)
        {
            RelocationHelper relocationHelper = new RelocationHelper(outputStream, defaultImageBase, peFile);

            if (corHeaderBuilder != null)
            {
                relocationHelper.CopyToFilePosition(corHeaderFileOffset);
                UpdateCorHeader(corHeaderBuilder);
                BlobBuilder corHeaderBlob = new BlobBuilder();
                corHeaderBuilder.WriteTo(corHeaderBlob);
                int writtenSize = corHeaderBlob.Count;
                corHeaderBlob.WriteContentTo(outputStream);
                relocationHelper.AdvanceOutputPos(writtenSize);

                // Just skip the bytes that were emitted by the COR header writer
                byte[] skipBuffer = new byte[writtenSize];
                relocationHelper.CopyBytesToBuffer(skipBuffer, writtenSize);
            }

            // Traverse relocations in all sections in their RVA order
            foreach (Section section in _sections.OrderBy((sec) => sec.RVAWhenPlaced))
            {
                int rvaToFilePosDelta = section.FilePosWhenPlaced - section.RVAWhenPlaced;
                foreach (ObjectDataRelocations objectDataRelocs in section.Relocations)
                {
                    foreach (Relocation relocation in objectDataRelocs.Relocs)
                    {
                        // Process a single relocation
                        int relocationRVA     = section.RVAWhenPlaced + objectDataRelocs.Offset + relocation.Offset;
                        int relocationFilePos = relocationRVA + rvaToFilePosDelta;

                        // Flush parts of PE file before the relocation to the output stream
                        relocationHelper.CopyToFilePosition(relocationFilePos);

                        // Look up relocation target
                        SymbolTarget relocationTarget = _symbolMap[relocation.Target];
                        Section      targetSection    = _sections[relocationTarget.SectionIndex];
                        int          targetRVA        = targetSection.RVAWhenPlaced + relocationTarget.Offset;

                        // Apply the relocation
                        relocationHelper.ProcessRelocation(relocation.RelocType, relocationRVA, targetRVA);
                    }
                }
            }

            // Flush remaining PE file blocks after the last relocation
            relocationHelper.CopyRestOfFile();
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Emit built sections using the R2R PE writer.
        /// </summary>
        /// <param name="builder">Section builder to emit</param>
        /// <param name="machine">Target machine architecture</param>
        /// <param name="inputReader">Input MSIL reader</param>
        /// <param name="outputStream">Output stream for the final R2R PE file</param>
        public static void EmitR2R(
            this SectionBuilder builder,
            Machine machine,
            PEReader inputReader,
            Action <PEDirectoriesBuilder> directoriesUpdater,
            Stream outputStream)
        {
            R2RPEBuilder r2rBuilder = new R2RPEBuilder(
                machine: machine,
                peReader: inputReader,
                sectionNames: builder.GetSections(),
                sectionSerializer: builder.SerializeSection,
                directoriesUpdater: (PEDirectoriesBuilder directoriesBuilder) =>
            {
                builder.UpdateDirectories(directoriesBuilder);
                if (directoriesUpdater != null)
                {
                    directoriesUpdater(directoriesBuilder);
                }
            });

            BlobBuilder outputPeFile = new BlobBuilder();

            r2rBuilder.Serialize(outputPeFile);

            CorHeaderBuilder corHeader = r2rBuilder.CorHeader;

            if (corHeader != null)
            {
                corHeader.Flags = (r2rBuilder.CorHeader.Flags & ~CorFlags.ILOnly) | CorFlags.ILLibrary;

                corHeader.MetadataDirectory                = r2rBuilder.RelocateDirectoryEntry(corHeader.MetadataDirectory);
                corHeader.ResourcesDirectory               = r2rBuilder.RelocateDirectoryEntry(corHeader.ResourcesDirectory);
                corHeader.StrongNameSignatureDirectory     = r2rBuilder.RelocateDirectoryEntry(corHeader.StrongNameSignatureDirectory);
                corHeader.CodeManagerTableDirectory        = r2rBuilder.RelocateDirectoryEntry(corHeader.CodeManagerTableDirectory);
                corHeader.VtableFixupsDirectory            = r2rBuilder.RelocateDirectoryEntry(corHeader.VtableFixupsDirectory);
                corHeader.ExportAddressTableJumpsDirectory = r2rBuilder.RelocateDirectoryEntry(corHeader.ExportAddressTableJumpsDirectory);
                corHeader.ManagedNativeHeaderDirectory     = r2rBuilder.RelocateDirectoryEntry(corHeader.ManagedNativeHeaderDirectory);

                builder.UpdateCorHeader(corHeader);
            }

            builder.RelocateOutputFile(
                outputPeFile,
                inputReader.PEHeaders.PEHeader.ImageBase,
                corHeader,
                r2rBuilder.CorHeaderFileOffset,
                outputStream);

            r2rBuilder.RelocateMetadataBlob(outputStream);
        }
Ejemplo n.º 5
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
                    {
                        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);
        }