Exemple #1
0
        /// <summary>
        /// Update the PE file directories. Currently this is used to update the export symbol table
        /// when export symbols have been added to the section builder.
        /// </summary>
        /// <param name="directoriesBuilder">PE directory builder to update</param>
        public void UpdateDirectories(PEDirectoriesBuilder directoriesBuilder)
        {
            if (_corHeaderSymbol != null)
            {
                SymbolTarget symbolTarget = _symbolMap[_corHeaderSymbol];
                Section      section      = _sections[symbolTarget.SectionIndex];
                Debug.Assert(section.RVAWhenPlaced != 0);
                directoriesBuilder.CorHeaderTable = new DirectoryEntry(section.RVAWhenPlaced + symbolTarget.Offset, _corHeaderSize);
            }

            if (_exportDirectoryEntry.Size != 0)
            {
                directoriesBuilder.ExportTable = _exportDirectoryEntry;
            }

            int relocationTableRVA = directoriesBuilder.BaseRelocationTable.RelativeVirtualAddress;

            if (relocationTableRVA == 0)
            {
                relocationTableRVA = _relocationDirectoryEntry.RelativeVirtualAddress;
            }
            directoriesBuilder.BaseRelocationTable = new DirectoryEntry(
                relocationTableRVA,
                directoriesBuilder.BaseRelocationTable.Size + _relocationDirectoryEntry.Size);

            if (_entryPointSymbol != null)
            {
                SymbolTarget symbolTarget = _symbolMap[_entryPointSymbol];
                Section      section      = _sections[symbolTarget.SectionIndex];
                Debug.Assert(section.RVAWhenPlaced != 0);
                directoriesBuilder.AddressOfEntryPoint = section.RVAWhenPlaced + symbolTarget.Offset;
            }
        }
Exemple #2
0
        /// <summary>
        /// Update the PE file directories. Currently this is used to update the export symbol table
        /// when export symbols have been added to the section builder.
        /// </summary>
        /// <param name="directoriesBuilder">PE directory builder to update</param>
        public void UpdateDirectories(PEDirectoriesBuilder directoriesBuilder)
        {
            if (_corHeaderSymbol != null)
            {
                SymbolTarget symbolTarget = _symbolMap[_corHeaderSymbol];
                Section      section      = _sections[symbolTarget.SectionIndex];
                Debug.Assert(section.RVAWhenPlaced != 0);
                directoriesBuilder.CorHeaderTable = new DirectoryEntry(section.RVAWhenPlaced + symbolTarget.Offset, _corHeaderSize);
            }

            if (_win32ResourcesSymbol != null)
            {
                SymbolTarget symbolTarget = _symbolMap[_win32ResourcesSymbol];
                Section      section      = _sections[symbolTarget.SectionIndex];
                Debug.Assert(section.RVAWhenPlaced != 0);

                // Windows has a bug in its resource processing logic that occurs when
                // 1. A PE file is loaded as a data file
                // 2. The resource data found in the resources has an RVA which has a magnitude greater than the size of the section which holds the resources
                // 3. The offset of the start of the resource data from the start of the section is not zero.
                //
                // As it is impossible to effect condition 1 in the compiler, and changing condition 2 would require bloating the virtual size of the sections,
                // instead require that the resource data is located at offset 0 within the section.
                // We achieve that by sorting the Win32ResourcesNode as the first node.
                Debug.Assert(symbolTarget.Offset == 0);
                directoriesBuilder.ResourceTable = new DirectoryEntry(section.RVAWhenPlaced + symbolTarget.Offset, _win32ResourcesSize);
            }

            if (_exportDirectoryEntry.Size != 0)
            {
                directoriesBuilder.ExportTable = _exportDirectoryEntry;
            }

            int relocationTableRVA = directoriesBuilder.BaseRelocationTable.RelativeVirtualAddress;

            if (relocationTableRVA == 0)
            {
                relocationTableRVA = _relocationDirectoryEntry.RelativeVirtualAddress;
            }
            directoriesBuilder.BaseRelocationTable = new DirectoryEntry(
                relocationTableRVA,
                directoriesBuilder.BaseRelocationTable.Size + _relocationDirectoryEntry.Size);

            if (_entryPointSymbol != null)
            {
                SymbolTarget symbolTarget = _symbolMap[_entryPointSymbol];
                Section      section      = _sections[symbolTarget.SectionIndex];
                Debug.Assert(section.RVAWhenPlaced != 0);
                directoriesBuilder.AddressOfEntryPoint = section.RVAWhenPlaced + symbolTarget.Offset;
            }

            if (_debugDirectorySymbol != null)
            {
                SymbolTarget symbolTarget = _symbolMap[_debugDirectorySymbol];
                Section      section      = _sections[symbolTarget.SectionIndex];
                Debug.Assert(section.RVAWhenPlaced != 0);
                directoriesBuilder.DebugTable = new DirectoryEntry(section.RVAWhenPlaced + symbolTarget.Offset, _debugDirectorySize);
            }
        }
Exemple #3
0
        /// <summary>
        /// Look up final file position for a given symbol. This assumes the section have already been placed.
        /// </summary>
        /// <param name="symbol">Symbol to look up</param>
        /// <returns>File position of the symbol, from the begining of the emitted image</returns>
        public int GetSymbolFilePosition(ISymbolNode symbol)
        {
            SymbolTarget symbolTarget = _symbolMap[symbol];
            Section      section      = _sections[symbolTarget.SectionIndex];

            Debug.Assert(section.RVAWhenPlaced != 0);
            return(section.FilePosWhenPlaced + symbolTarget.Offset);
        }
Exemple #4
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);
     }
 }
Exemple #5
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();
        }
        public void AddSymbolForRange(ISymbolNode symbol, ISymbolNode firstNode, ISymbolNode secondNode)
        {
            SymbolTarget firstSymbolTarget  = _symbolMap[firstNode];
            SymbolTarget secondSymbolTarget = _symbolMap[secondNode];

            Debug.Assert(firstSymbolTarget.SectionIndex == secondSymbolTarget.SectionIndex);
            Debug.Assert(firstSymbolTarget.Offset <= secondSymbolTarget.Offset);

            _symbolMap.Add(symbol, new SymbolTarget(
                               sectionIndex: firstSymbolTarget.SectionIndex,
                               offset: firstSymbolTarget.Offset,
                               size: secondSymbolTarget.Offset - firstSymbolTarget.Offset + secondSymbolTarget.Size
                               ));
        }
Exemple #7
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,
            Stream outputStream)
        {
            RelocationHelper relocationHelper = new RelocationHelper(outputStream, defaultImageBase, peFile);

            // 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 (PlacedObjectData placedObjectData in section.PlacedObjectDataToRelocate)
                {
                    foreach (Relocation relocation in placedObjectData.Relocs)
                    {
                        // Process a single relocation
                        int relocationRVA     = section.RVAWhenPlaced + placedObjectData.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;
                        int          filePosWhenPlaced = targetSection.FilePosWhenPlaced + relocationTarget.Offset;

                        // If relocating to a node's size, switch out the target RVA with data length
                        if (relocation.RelocType == RelocType.IMAGE_REL_SYMBOL_SIZE)
                        {
                            targetRVA = relocationTarget.Size;
                        }

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

            // Flush remaining PE file blocks after the last relocation
            relocationHelper.CopyRestOfFile();
        }
Exemple #8
0
        /// <summary>
        /// Serialize the export symbol table into the export section.
        /// </summary>
        /// <param name="location">RVA and file location of the .edata section</param>
        private BlobBuilder SerializeExportSection(SectionLocation sectionLocation)
        {
            _exportSymbols.MergeSort((es1, es2) => StringComparer.Ordinal.Compare(es1.Name, es2.Name));

            BlobBuilder builder = new BlobBuilder();

            int minOrdinal = int.MaxValue;
            int maxOrdinal = int.MinValue;

            // First, emit the name table and store the name RVA's for the individual export symbols
            // Also, record the ordinal range.
            foreach (ExportSymbol symbol in _exportSymbols)
            {
                symbol.NameRVAWhenPlaced = sectionLocation.RelativeVirtualAddress + builder.Count;
                builder.WriteUTF8(symbol.Name);
                builder.WriteByte(0);

                if (symbol.Ordinal < minOrdinal)
                {
                    minOrdinal = symbol.Ordinal;
                }
                if (symbol.Ordinal > maxOrdinal)
                {
                    maxOrdinal = symbol.Ordinal;
                }
            }

            // Emit the DLL name
            int dllNameRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            builder.WriteUTF8(_dllNameForExportDirectoryTable);
            builder.WriteByte(0);

            int[] addressTable = new int[maxOrdinal - minOrdinal + 1];

            // Emit the name pointer table; it should be alphabetically sorted.
            // Also, we can now fill in the export address table as we've detected its size
            // in the previous pass.
            int namePointerTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            foreach (ExportSymbol symbol in _exportSymbols)
            {
                builder.WriteInt32(symbol.NameRVAWhenPlaced);
                SymbolTarget symbolTarget  = _symbolMap[symbol.Symbol];
                Section      symbolSection = _sections[symbolTarget.SectionIndex];
                Debug.Assert(symbolSection.RVAWhenPlaced != 0);
                addressTable[symbol.Ordinal - minOrdinal] = symbolSection.RVAWhenPlaced + symbolTarget.Offset;
            }

            // Emit the ordinal table
            int ordinalTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            foreach (ExportSymbol symbol in _exportSymbols)
            {
                builder.WriteUInt16((ushort)(symbol.Ordinal - minOrdinal));
            }

            // Emit the address table
            int addressTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            foreach (int addressTableEntry in addressTable)
            {
                builder.WriteInt32(addressTableEntry);
            }

            // Emit the export directory table
            int exportDirectoryTableRVA = sectionLocation.RelativeVirtualAddress + builder.Count;

            // +0x00: reserved
            builder.WriteInt32(0);
            // +0x04: TODO: time/date stamp
            builder.WriteInt32(0);
            // +0x08: major version
            builder.WriteInt16(0);
            // +0x0A: minor version
            builder.WriteInt16(0);
            // +0x0C: DLL name RVA
            builder.WriteInt32(dllNameRVA);
            // +0x10: ordinal base
            builder.WriteInt32(minOrdinal);
            // +0x14: number of entries in the address table
            builder.WriteInt32(addressTable.Length);
            // +0x18: number of name pointers
            builder.WriteInt32(_exportSymbols.Count);
            // +0x1C: export address table RVA
            builder.WriteInt32(addressTableRVA);
            // +0x20: name pointer RVV
            builder.WriteInt32(namePointerTableRVA);
            // +0x24: ordinal table RVA
            builder.WriteInt32(ordinalTableRVA);
            int exportDirectorySize = sectionLocation.RelativeVirtualAddress + builder.Count - exportDirectoryTableRVA;

            _exportDirectoryEntry = new DirectoryEntry(relativeVirtualAddress: exportDirectoryTableRVA, size: exportDirectorySize);

            return(builder);
        }