Beispiel #1
0
        protected void WriteData(MDWriterStream stream, List <byte[]> newData, byte[] tempBuffer)
        {
            if (newData.Count == 0)
            {
                return;
            }
            int tempBufferIndex = 0;

            foreach (var data in newData)
            {
                int bytesLeft = tempBuffer.Length - tempBufferIndex;
                if (data.Length > bytesLeft)
                {
                    stream.Write(tempBuffer, 0, tempBufferIndex);
                    tempBufferIndex = 0;
                }
                if (data.Length > tempBuffer.Length)
                {
                    Debug.Assert(tempBufferIndex == 0);
                    stream.Write(data);
                }
                else
                {
                    Array.Copy(data, 0, tempBuffer, tempBufferIndex, data.Length);
                    tempBufferIndex += data.Length;
                }
            }
            if (tempBufferIndex > 0)
            {
                stream.Write(tempBuffer, 0, tempBufferIndex);
            }
        }
Beispiel #2
0
        public override void Finish(MDWriter mdWriter, MDWriterStream stream)
        {
            stream.Position = cor20HeaderMetadataDataDirPosition;
            Debug.Assert(mdData.RVA != 0);
            Debug.Assert(mdData.Size != 0);
            stream.Write(mdData.RVA);
            stream.Write(mdData.Size);

            if (!(snData is null))
            {
                stream.Position = cor20HeaderStrongnameDataDirPosition;
                Debug.Assert(snData.RVA != 0);
                Debug.Assert(snData.Size != 0);
                stream.Write(snData.RVA);
                stream.Write(snData.Size);
            }
        }
Beispiel #3
0
        public override void Write(MDWriter mdWriter, uint rva, MDWriterStream stream)
        {
            mdWriter.WriteDataDirectory(14, rva, headerSize);
            stream.Write(headerSize);
            var cor20 = mdWriter.MetadataEditor.RealMetadata.ImageCor20Header;

            stream.Write(cor20.MajorRuntimeVersion);
            stream.Write(cor20.MinorRuntimeVersion);
            cor20HeaderMetadataDataDirPosition = stream.Position;
            stream.Position += 8;            // Metadata data directory, updated later
            var flags = cor20.Flags;

            flags &= ~ComImageFlags.NativeEntryPoint;
            if (snData is null)
            {
                flags &= ~ComImageFlags.StrongNameSigned;
            }
            else
            {
                flags |= ComImageFlags.StrongNameSigned;
            }
            stream.Write((uint)flags);
            if ((cor20.Flags & ComImageFlags.NativeEntryPoint) == 0)
            {
                stream.Write(cor20.EntryPointToken_or_RVA);
            }
            else
            {
                stream.Position += 4;
            }
            stream.Position += 8;            // .NET resources
            cor20HeaderStrongnameDataDirPosition = stream.Position;
            stream.Position += 8;            // Strong name signature
            stream.Position += 8;            // Code manager table
            stream.Position += 8;            // Vtable fixups
            stream.Position += 8;            // Export address table jumps
            stream.Position += 8;            // Managed native header
        }
Beispiel #4
0
        public void Write()
        {
            var  peImage = mdEditor.RealMetadata.PEImage;
            bool is32Bit = peImage.ImageNTHeaders.OptionalHeader is ImageOptionalHeader32;

            sections.Add(textSection = new PESection(".text", 0x60000020));

            StrongNameSignatureSectionData snData = null;
            var cor20 = mdEditor.RealMetadata.ImageCor20Header;

            if ((cor20.Flags & ComImageFlags.StrongNameSigned) != 0 && cor20.StrongNameSignature.Size != 0 && cor20.StrongNameSignature.VirtualAddress != 0)
            {
                snData = new StrongNameSignatureSectionData(cor20.StrongNameSignature.Size);
            }

            if (snData != null)
            {
                textSection.SectionData.Add(snData);
            }
            var mdData = new DotNetMetadataSectionData(mdEditor);

            textSection.SectionData.Add(new ImageCor20HeaderSectionData(mdData, snData));
            textSection.SectionData.Add(mdData);

            // DOS MZ header
            stream.Write(dosHeader);

            // PE\0\0
            Debug.Assert(stream.Position == BitConverter.ToUInt32(dosHeader, 0x7C));
            stream.Write(0x00004550);

            // IMAGE_FILE_HEADER
            var ifh = peImage.ImageNTHeaders.FileHeader;

            stream.Write((ushort)ifh.Machine);
            Debug.Assert(sections.Count <= ushort.MaxValue);
            stream.Write((ushort)sections.Count);
            stream.Write(ifh.TimeDateStamp);
            stream.Position += 8;            // PointerToSymbolTable & NumberOfSymbols
            stream.Write((ushort)(is32Bit ? 0xE0 : 0xF0));
            stream.Write((ushort)ifh.Characteristics);

            // IMAGE_OPTIONAL_HEADER
            var optHeaderPos = stream.Position;

            if (is32Bit)
            {
                var opt   = (ImageOptionalHeader32)peImage.ImageNTHeaders.OptionalHeader;
                var start = stream.Position;
                stream.Write(opt.Magic);
                stream.Write(opt.MajorLinkerVersion);
                stream.Write(opt.MinorLinkerVersion);
                // SizeOfCode, SizeOfInitializedData, SizeOfUninitializedData
                // AddressOfEntryPoint, BaseOfCode, BaseOfData
                stream.Position += 6 * 4;
                stream.Write((uint)opt.ImageBase);
                stream.Write((uint)SectionAlignment);
                stream.Write((uint)FileAlignment);
                stream.Write(opt.MajorOperatingSystemVersion);
                stream.Write(opt.MinorOperatingSystemVersion);
                stream.Write(opt.MajorImageVersion);
                stream.Write(opt.MinorImageVersion);
                stream.Write(opt.MajorSubsystemVersion);
                stream.Write(opt.MinorSubsystemVersion);
                stream.Write(opt.Win32VersionValue);
                // SizeOfImage, SizeOfHeaders, CheckSum
                stream.Position += 3 * 4;
                stream.Write((ushort)opt.Subsystem);
                stream.Write((ushort)opt.DllCharacteristics);
                stream.Write((uint)opt.SizeOfStackReserve);
                stream.Write((uint)opt.SizeOfStackCommit);
                stream.Write((uint)opt.SizeOfHeapReserve);
                stream.Write((uint)opt.SizeOfHeapCommit);
                stream.Write(opt.LoaderFlags);
                stream.Write(0x10);                // NumberOfRvaAndSizes
                Debug.Assert((stream.Position - start) == 0x60);
            }
            else
            {
                var opt   = (ImageOptionalHeader64)peImage.ImageNTHeaders.OptionalHeader;
                var start = stream.Position;
                stream.Write(opt.Magic);
                stream.Write(opt.MajorLinkerVersion);
                stream.Write(opt.MinorLinkerVersion);
                // SizeOfCode, SizeOfInitializedData, SizeOfUninitializedData
                // AddressOfEntryPoint, BaseOfCode
                stream.Position += 5 * 4;
                stream.Write(opt.ImageBase);
                stream.Write((uint)SectionAlignment);
                stream.Write((uint)FileAlignment);
                stream.Write(opt.MajorOperatingSystemVersion);
                stream.Write(opt.MinorOperatingSystemVersion);
                stream.Write(opt.MajorImageVersion);
                stream.Write(opt.MinorImageVersion);
                stream.Write(opt.MajorSubsystemVersion);
                stream.Write(opt.MinorSubsystemVersion);
                stream.Write(opt.Win32VersionValue);
                // SizeOfImage, SizeOfHeaders, CheckSum
                stream.Position += 3 * 4;
                stream.Write((ushort)opt.Subsystem);
                stream.Write((ushort)opt.DllCharacteristics);
                stream.Write(opt.SizeOfStackReserve);
                stream.Write(opt.SizeOfStackCommit);
                stream.Write(opt.SizeOfHeapReserve);
                stream.Write(opt.SizeOfHeapCommit);
                stream.Write(opt.LoaderFlags);
                stream.Write(0x10);                // NumberOfRvaAndSizes
                Debug.Assert((stream.Position - start) == 0x70);
            }

            // IMAGE_DATA_DIRECTORY
            dataDirPosition  = stream.Position;
            stream.Position += 0x10 * 8;

            // IMAGE_SECTION_HEADER
            var sectionPos = stream.Position;

            foreach (var section in sections)
            {
                Debug.Assert(section.Name.Length == 8);
                stream.Write(section.Name);
                // VirtualSize, VirtualAddress, SizeOfRawData, PointerToRawData
                // PointerToRelocations, PointerToLinenumbers, NumberOfRelocations, NumberOfLinenumbers
                stream.Position += 6 * 4 + 2 * 2;
                stream.Write(section.Characteristics);
            }
            uint headerLength = (uint)stream.Position;

            AlignUp(FileAlignment);

            // Write all sections
            uint rva = SectionAlignment;

            foreach (var section in sections)
            {
                section.VirtualAddress   = rva;
                section.PointerToRawData = (uint)stream.Position;
                foreach (var data in section.SectionData)
                {
                    var pos = stream.Position;
                    AlignUp(data.Alignment);
                    rva += (uint)(stream.Position - pos);

                    pos = stream.Position;
                    data.Write(this, rva, stream);
                    rva += (uint)(stream.Position - pos);
                }
                Debug.Assert(stream.Position != section.PointerToRawData);
                if (stream.Position == section.PointerToRawData)
                {
                    stream.Position++;
                }
                section.VirtualSize   = (uint)stream.Position - section.PointerToRawData;
                section.SizeOfRawData = ((uint)stream.Position - section.PointerToRawData + FileAlignment - 1) & ~(FileAlignment - 1);
                rva = (rva + SectionAlignment - 1) & ~(SectionAlignment - 1);
                AlignUp(FileAlignment);
            }

            stream.Length = stream.Position;

            // Update IMAGE_SECTION_HEADER
            stream.Position = sectionPos;
            foreach (var section in sections)
            {
                stream.Position += 8;
                stream.Write(section.VirtualSize);
                stream.Write(section.VirtualAddress);
                stream.Write(section.SizeOfRawData);
                stream.Write(section.PointerToRawData);
                stream.Position += 16;
            }

            // Update IMAGE_OPTIONAL_HEADER
            var sectionSizes = new SectionSizes(FileAlignment, SectionAlignment, headerLength, () => GetSectionSizeInfos());

            stream.Position = optHeaderPos;
            if (is32Bit)
            {
                var opt = (ImageOptionalHeader32)peImage.ImageNTHeaders.OptionalHeader;
                stream.Position += 4;
                stream.Write(sectionSizes.SizeOfCode);
                stream.Write(sectionSizes.SizeOfInitdData);
                stream.Write(sectionSizes.SizeOfUninitdData);
                stream.Position += 4;
                stream.Write(sectionSizes.BaseOfCode);
                stream.Write(sectionSizes.BaseOfData);
                stream.Position += 0x1C;
                stream.Write(sectionSizes.SizeOfImage);
                stream.Write(sectionSizes.SizeOfHeaders);
            }
            else
            {
                var opt = (ImageOptionalHeader64)peImage.ImageNTHeaders.OptionalHeader;
                stream.Position += 4;
                stream.Write(sectionSizes.SizeOfCode);
                stream.Write(sectionSizes.SizeOfInitdData);
                stream.Write(sectionSizes.SizeOfUninitdData);
                stream.Position += 4;
                stream.Write(sectionSizes.BaseOfCode);
                stream.Position += 0x20;
                stream.Write(sectionSizes.SizeOfImage);
                stream.Write(sectionSizes.SizeOfHeaders);
            }

            foreach (var section in sections)
            {
                foreach (var data in section.SectionData)
                {
                    data.Finish(this, stream);
                }
            }
        }
Beispiel #5
0
        public unsafe override void Write(MDWriter mdWriter, MDWriterStream stream, byte[] tempBuffer)
        {
            var tblStream = mdWriter.MetadataEditor.RealMetadata.TablesStream;

            stream.Write(tblStream.Reserved1);
            stream.Write((byte)(tblStream.Version >> 8));
            stream.Write((byte)tblStream.Version);
            stream.Write((byte)mdStreamFlags);
            stream.Write((byte)1);
            stream.Write(GetValidMask(tablesHeap));
            stream.Write(GetSortedMask(tablesHeap, tblStream.SortedMask));
            var rowCounts = new uint[tablesHeap.TableInfos.Length];
            var infos     = tablesHeap.TableInfos;

            for (int i = 0; i < infos.Length; i++)
            {
                if (tablesToIgnore[i])
                {
                    continue;
                }
                var info = infos[i];
                if (info != null && !info.IsEmpty)
                {
                    rowCounts[i] = info.Rows;
                    stream.Write(info.Rows);
                }
            }

            var dnTableSizes = new DotNetTableSizes();
            var tableInfos   = dnTableSizes.CreateTables((byte)(tblStream.Version >> 8), (byte)tblStream.Version);

            dnTableSizes.InitializeSizes((mdStreamFlags & MDStreamFlags.BigStrings) != 0,
                                         (mdStreamFlags & MDStreamFlags.BigGUID) != 0,
                                         (mdStreamFlags & MDStreamFlags.BigBlob) != 0,
                                         rowCounts, rowCounts);

            long totalSize = 0;

            for (int i = 0; i < infos.Length; i++)
            {
                if (tablesToIgnore[i])
                {
                    continue;
                }
                var info = infos[i];
                if (info != null && !info.IsEmpty)
                {
                    totalSize += (long)info.Rows * tableInfos[i].RowSize;
                }
            }

            // NOTE: We don't write method bodies or field data, the compiler shouldn't
            // read Method.RVA. We also don't write the FieldRVA table.

            // PERF: Write to a temp buffer followed by a call to stream.Write(byte[]). It's faster
            // than calling stream.Write() for every row + column.

            var tablesPos       = stream.Position;
            int tempBufferIndex = 0;

            for (int i = 0; i < infos.Length; i++)
            {
                if (tablesToIgnore[i])
                {
                    continue;
                }
                var info = infos[i];
                if (info == null || info.IsEmpty)
                {
                    continue;
                }

                var tableWriter = TableWriter.Create(info);
                var mdTable     = info.MDTable;

                var  tbl             = tableInfos[i];
                var  columns         = tbl.Columns;
                var  rows            = tableWriter.Rows;
                uint currentRowIndex = 0;
                var  rowSize         = (uint)tbl.RowSize;
                Debug.Assert(tempBuffer.Length >= rowSize, "Temp buffer is too small");

                // If there are no changes in the original metadata or layout, just copy everything
                uint unmodifiedRows = tableWriter.FirstModifiedRowId - 1;
                if (unmodifiedRows > 0 && Equals(mdTable.TableInfo, tbl))
                {
                    if (tempBufferIndex > 0)
                    {
                        stream.Write(tempBuffer, 0, tempBufferIndex);
                        tempBufferIndex = 0;
                    }

                    stream.Write((byte *)mdWriter.ModuleData.Pointer + (int)mdTable.StartOffset, (int)(unmodifiedRows * mdTable.RowSize));

                    Debug.Assert(unmodifiedRows <= rows);
                    rows            -= unmodifiedRows;
                    currentRowIndex += unmodifiedRows;
                }

                while (rows > 0)
                {
                    int  bytesLeft = tempBuffer.Length - tempBufferIndex;
                    uint maxRows   = Math.Min((uint)bytesLeft / rowSize, rows);
                    if (maxRows == 0)
                    {
                        stream.Write(tempBuffer, 0, tempBufferIndex);
                        tempBufferIndex = 0;

                        bytesLeft = tempBuffer.Length;
                        maxRows   = Math.Min((uint)bytesLeft / rowSize, rows);
                    }
                    Debug.Assert(maxRows > 0);

                    for (uint endRowIndex = currentRowIndex + maxRows; currentRowIndex < endRowIndex; currentRowIndex++, tempBufferIndex += (int)rowSize)
                    {
                        tableWriter.WriteRow(currentRowIndex, columns, tempBuffer, tempBufferIndex);
                    }
                    rows -= maxRows;
                }
            }
            if (tempBufferIndex > 0)
            {
                stream.Write(tempBuffer, 0, tempBufferIndex);
            }
            if (tablesPos + totalSize != stream.Position)
            {
                throw new InvalidOperationException();
            }
        }