Ejemplo n.º 1
0
 internal TextSection(PEWriter peWriter, CliHeader cliHeader, ModuleBuilder moduleBuilder, int strongNameSignatureLength)
 {
     this.peWriter                  = peWriter;
     this.cliHeader                 = cliHeader;
     this.moduleBuilder             = moduleBuilder;
     this.strongNameSignatureLength = (uint)strongNameSignatureLength;
 }
Ejemplo n.º 2
0
 internal TextSection(PEWriter peWriter, CliHeader cliHeader, ModuleBuilder moduleBuilder, bool strongName)
 {
     this.peWriter      = peWriter;
     this.cliHeader     = cliHeader;
     this.moduleBuilder = moduleBuilder;
     this.strongName    = strongName;
 }
Ejemplo n.º 3
0
 internal TextSection(PEWriter peWriter, CliHeader cliHeader, ModuleBuilder moduleBuilder, int strongNameSignatureLength)
 {
     this.peWriter                  = peWriter;
     this.cliHeader                 = cliHeader;
     this.moduleBuilder             = moduleBuilder;
     this.strongNameSignatureLength = (uint)strongNameSignatureLength;
     if (moduleBuilder.unmanagedExports.Count != 0)
     {
         this.exportTables = new ExportTables(this);
     }
 }
Ejemplo n.º 4
0
        private static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder,
                                            PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine,
                                            ResourceSection resources, int entryPointToken, Stream stream)
        {
            moduleBuilder.ApplyUnmanagedExports(imageFileMachine);
            moduleBuilder.FixupMethodBodyTokens();

            moduleBuilder.ModuleTable.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleBuilder.Guids.Add(moduleBuilder.ModuleVersionId), 0, 0);

            if (moduleBuilder.UserStrings.IsEmpty)
            {
                // for compat with Ref.Emit, if there aren't any user strings, we add one
                moduleBuilder.UserStrings.Add(" ");
            }

            if (resources != null)
            {
                resources.Finish();
            }

            PEWriter writer = new PEWriter(stream);

            switch (imageFileMachine)
            {
            case ImageFileMachine.I386:
                writer.Headers.FileHeader.Machine                = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386;
                writer.Headers.FileHeader.Characteristics       |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE;
                writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x100000);
                break;

            case ImageFileMachine.ARM:
                writer.Headers.FileHeader.Machine                = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM;
                writer.Headers.FileHeader.Characteristics       |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE;
                writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x100000);
                break;

            case ImageFileMachine.AMD64:
                writer.Headers.FileHeader.Machine                = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64;
                writer.Headers.FileHeader.Characteristics       |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
                writer.Headers.FileHeader.SizeOfOptionalHeader   = 0xF0;
                writer.Headers.OptionalHeader.Magic              = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
                writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x400000);
                writer.Headers.OptionalHeader.SizeOfStackCommit  = 0x4000;
                writer.Headers.OptionalHeader.SizeOfHeapCommit   = 0x2000;
                break;

            case ImageFileMachine.IA64:
                writer.Headers.FileHeader.Machine                = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64;
                writer.Headers.FileHeader.Characteristics       |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
                writer.Headers.FileHeader.SizeOfOptionalHeader   = 0xF0;
                writer.Headers.OptionalHeader.Magic              = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
                writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x400000);
                writer.Headers.OptionalHeader.SizeOfStackCommit  = 0x4000;
                writer.Headers.OptionalHeader.SizeOfHeapCommit   = 0x2000;
                break;

            default:
                throw new ArgumentOutOfRangeException("imageFileMachine");
            }
            if (fileKind == PEFileKinds.Dll)
            {
                writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_DLL;
            }

            switch (fileKind)
            {
            case PEFileKinds.WindowApplication:
                writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_GUI;
                break;

            default:
                writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_CUI;
                break;
            }
            writer.Headers.OptionalHeader.DllCharacteristics =
                IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE |
                IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NO_SEH |
                IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NX_COMPAT |
                IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE;

            CliHeader cliHeader = new CliHeader();

            cliHeader.Cb = 0x48;
            cliHeader.MajorRuntimeVersion = 2;
            cliHeader.MinorRuntimeVersion = moduleBuilder.MDStreamVersion < 0x20000 ? (ushort)0 : (ushort)5;
            if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0)
            {
                cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_ILONLY;
            }
            if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0)
            {
                cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED;
            }
            if ((portableExecutableKind & PortableExecutableKinds.Preferred32Bit) != 0)
            {
                cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED;
            }
            if (keyPair != null)
            {
                cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_STRONGNAMESIGNED;
            }
            if (moduleBuilder.IsPseudoToken(entryPointToken))
            {
                entryPointToken = moduleBuilder.ResolvePseudoToken(entryPointToken);
            }
            cliHeader.EntryPointToken = (uint)entryPointToken;

            moduleBuilder.Strings.Freeze();
            moduleBuilder.UserStrings.Freeze();
            moduleBuilder.Guids.Freeze();
            moduleBuilder.Blobs.Freeze();
            MetadataWriter mw = new MetadataWriter(moduleBuilder, stream);

            moduleBuilder.Tables.Freeze(mw);
            TextSection code = new TextSection(writer, cliHeader, moduleBuilder, ComputeStrongNameSignatureLength(publicKey));

            // Export Directory
            if (code.ExportDirectoryLength != 0)
            {
                writer.Headers.OptionalHeader.DataDirectory[0].VirtualAddress = code.ExportDirectoryRVA;
                writer.Headers.OptionalHeader.DataDirectory[0].Size           = code.ExportDirectoryLength;
            }

            // Import Directory
            if (code.ImportDirectoryLength != 0)
            {
                writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA;
                writer.Headers.OptionalHeader.DataDirectory[1].Size           = code.ImportDirectoryLength;
            }

            // Import Address Table Directory
            if (code.ImportAddressTableLength != 0)
            {
                writer.Headers.OptionalHeader.DataDirectory[12].VirtualAddress = code.ImportAddressTableRVA;
                writer.Headers.OptionalHeader.DataDirectory[12].Size           = code.ImportAddressTableLength;
            }

            // COM Descriptor Directory
            writer.Headers.OptionalHeader.DataDirectory[14].VirtualAddress = code.ComDescriptorRVA;
            writer.Headers.OptionalHeader.DataDirectory[14].Size           = code.ComDescriptorLength;

            // Debug Directory
            if (code.DebugDirectoryLength != 0)
            {
                writer.Headers.OptionalHeader.DataDirectory[6].VirtualAddress = code.DebugDirectoryRVA;
                writer.Headers.OptionalHeader.DataDirectory[6].Size           = code.DebugDirectoryLength;
            }

            // we need to start by computing the number of sections, because code.PointerToRawData depends on that
            writer.Headers.FileHeader.NumberOfSections = 1;

            if (moduleBuilder.initializedData.Length != 0)
            {
                // .sdata
                writer.Headers.FileHeader.NumberOfSections++;
            }

            if (resources != null)
            {
                // .rsrc
                writer.Headers.FileHeader.NumberOfSections++;
            }

            if (imageFileMachine != ImageFileMachine.ARM)
            {
                // .reloc
                writer.Headers.FileHeader.NumberOfSections++;
            }

            SectionHeader text = new SectionHeader();

            text.Name             = ".text";
            text.VirtualAddress   = code.BaseRVA;
            text.VirtualSize      = (uint)code.Length;
            text.PointerToRawData = code.PointerToRawData;
            text.SizeOfRawData    = writer.ToFileAlignment((uint)code.Length);
            text.Characteristics  = SectionHeader.IMAGE_SCN_CNT_CODE | SectionHeader.IMAGE_SCN_MEM_EXECUTE | SectionHeader.IMAGE_SCN_MEM_READ;

            SectionHeader sdata = new SectionHeader();

            sdata.Name             = ".sdata";
            sdata.VirtualAddress   = text.VirtualAddress + writer.ToSectionAlignment(text.VirtualSize);
            sdata.VirtualSize      = (uint)moduleBuilder.initializedData.Length;
            sdata.PointerToRawData = text.PointerToRawData + text.SizeOfRawData;
            sdata.SizeOfRawData    = writer.ToFileAlignment((uint)moduleBuilder.initializedData.Length);
            sdata.Characteristics  = SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_MEM_WRITE;

            SectionHeader rsrc = new SectionHeader();

            rsrc.Name             = ".rsrc";
            rsrc.VirtualAddress   = sdata.VirtualAddress + writer.ToSectionAlignment(sdata.VirtualSize);
            rsrc.PointerToRawData = sdata.PointerToRawData + sdata.SizeOfRawData;
            rsrc.VirtualSize      = resources == null ? 0 : (uint)resources.Length;
            rsrc.SizeOfRawData    = writer.ToFileAlignment(rsrc.VirtualSize);
            rsrc.Characteristics  = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA;

            if (rsrc.SizeOfRawData != 0)
            {
                // Resource Directory
                writer.Headers.OptionalHeader.DataDirectory[2].VirtualAddress = rsrc.VirtualAddress;
                writer.Headers.OptionalHeader.DataDirectory[2].Size           = rsrc.VirtualSize;
            }

            SectionHeader reloc = new SectionHeader();

            reloc.Name           = ".reloc";
            reloc.VirtualAddress = rsrc.VirtualAddress + writer.ToSectionAlignment(rsrc.VirtualSize);
            if (imageFileMachine != ImageFileMachine.ARM)
            {
                reloc.VirtualSize = ((uint)moduleBuilder.unmanagedExports.Count + 1) * 12;
            }
            reloc.PointerToRawData = rsrc.PointerToRawData + rsrc.SizeOfRawData;
            reloc.SizeOfRawData    = writer.ToFileAlignment(reloc.VirtualSize);
            reloc.Characteristics  = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_DISCARDABLE;

            if (reloc.SizeOfRawData != 0)
            {
                // Base Relocation Directory
                writer.Headers.OptionalHeader.DataDirectory[5].VirtualAddress = reloc.VirtualAddress;
                writer.Headers.OptionalHeader.DataDirectory[5].Size           = reloc.VirtualSize;
            }

            writer.Headers.OptionalHeader.SizeOfCode              = text.SizeOfRawData;
            writer.Headers.OptionalHeader.SizeOfInitializedData   = sdata.SizeOfRawData + rsrc.SizeOfRawData + reloc.SizeOfRawData;
            writer.Headers.OptionalHeader.SizeOfUninitializedData = 0;
            writer.Headers.OptionalHeader.SizeOfImage             = reloc.VirtualAddress + writer.ToSectionAlignment(reloc.VirtualSize);
            writer.Headers.OptionalHeader.SizeOfHeaders           = text.PointerToRawData;
            writer.Headers.OptionalHeader.BaseOfCode              = code.BaseRVA;
            writer.Headers.OptionalHeader.BaseOfData              = sdata.VirtualAddress;
            writer.Headers.OptionalHeader.ImageBase = (ulong)moduleBuilder.__ImageBase;

            if (imageFileMachine == ImageFileMachine.IA64)
            {
                // apparently for IA64 AddressOfEntryPoint points to the address of the entry point
                // (i.e. there is an additional layer of indirection), so we add the offset to the pointer
                writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + 0x20;
            }
            else if (imageFileMachine != ImageFileMachine.ARM)
            {
                writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA;
            }

            writer.WritePEHeaders();
            writer.WriteSectionHeader(text);
            if (sdata.SizeOfRawData != 0)
            {
                writer.WriteSectionHeader(sdata);
            }
            if (rsrc.SizeOfRawData != 0)
            {
                writer.WriteSectionHeader(rsrc);
            }
            if (reloc.SizeOfRawData != 0)
            {
                writer.WriteSectionHeader(reloc);
            }

            stream.Seek(text.PointerToRawData, SeekOrigin.Begin);
            code.Write(mw, sdata.VirtualAddress);

            if (sdata.SizeOfRawData != 0)
            {
                stream.Seek(sdata.PointerToRawData, SeekOrigin.Begin);
                mw.Write(moduleBuilder.initializedData);
            }

            if (rsrc.SizeOfRawData != 0)
            {
                stream.Seek(rsrc.PointerToRawData, SeekOrigin.Begin);
                resources.Write(mw, rsrc.VirtualAddress);
            }

            if (reloc.SizeOfRawData != 0)
            {
                stream.Seek(reloc.PointerToRawData, SeekOrigin.Begin);
                code.WriteRelocations(mw);
            }

            // file alignment
            stream.SetLength(reloc.PointerToRawData + reloc.SizeOfRawData);

            // do the strong naming
            if (keyPair != null)
            {
                StrongName(stream, keyPair, writer.HeaderSize, text.PointerToRawData, code.StrongNameSignatureRVA - text.VirtualAddress + text.PointerToRawData, code.StrongNameSignatureLength);
            }

            if (moduleBuilder.symbolWriter != null)
            {
                moduleBuilder.WriteSymbolTokenMap();
                moduleBuilder.symbolWriter.Close();
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Reads the root structure from the metadata.
        /// </summary>
        /// <param name="header">The <see cref="CliHeader"/> which denotes the location of the information.</param>
        /// <param name="originalStream">The <see cref="FileStream"/> being read from.</param>
        /// <param name="reader">The <see cref="EndianAwareBinaryReader"/> which handles reads.</param>
        /// <param name="relativeVirtualAddress">The <see cref="UInt32"/> value which denotes the relative
        /// virtual address of the metadata header.</param>
        /// <param name="sourceImage"></param>
        internal void Read(CliHeader header, FileStream originalStream, EndianAwareBinaryReader reader, uint relativeVirtualAddress, PEImage sourceImage)
        {
            this.originalStream = originalStream;
            this.header         = header;
            this.streamPosition = relativeVirtualAddress;
            this.signature      = reader.ReadUInt32();
            if (this.signature != metadataSignature)
            {
                throw new BadImageFormatException();
            }
            this.depreciatedVersion.Read(reader);
            this.reserved          = reader.ReadUInt32();
            this.realVersionLength = reader.ReadInt32();
            byte[] version = new byte[(this.realVersionLength + 3) & ~3];//Make it a multiple of four.
            reader.Read(version, 0, version.Length);
            this.version       = version;
            this.reservedFlags = reader.ReadUInt16();
            int streamCount = 0;

            streamCount      = reader.ReadUInt16();
            this.sourceImage = sourceImage;
            for (int i = 0; i < streamCount; i++)
            {
                var currentHeader = new CliMetadataStreamHeader();
                currentHeader.Read(reader, sourceImage);
                switch (currentHeader.Name)
                {
                case "#Strings":
                    if (this.strings != null)
                    {
                        goto sectionExists;
                    }
                    this.strings = new CliMetadataStringsHeaderAndHeap(currentHeader, sourceImage.SyncObject);
                    this.ScanAndReadSection(sourceImage, strings, this.strings.Read);
                    break;

                case "#Blob":
                    if (this.blob != null)
                    {
                        goto sectionExists;
                    }
                    this.blob = new CliMetadataBlobHeaderAndHeap(currentHeader, this);
                    this.ScanAndReadSection(sourceImage, blob, this.blob.Read);
                    break;

                case "#US":
                    if (this.userStrings != null)
                    {
                        goto sectionExists;
                    }
                    this.userStrings = new CliMetadataUserStringsHeaderAndHeap(currentHeader, sourceImage.SyncObject);
                    this.ScanAndReadSection(sourceImage, this.userStrings, this.userStrings.Read);
                    break;

                case "#GUID":
                    if (this.guids != null)
                    {
                        goto sectionExists;
                    }
                    this.guids = new CliMetadataGuidHeaderAndHeap(currentHeader, sourceImage.SyncObject);
                    this.ScanAndReadSection(sourceImage, guids, this.guids.Read);
                    break;

                case "#-":     //https://github.com/jbevain/cecil/blob/8b689ecdc890cbf3715ba8775de1d713d71f09f3/Mono.Cecil.PE/ImageReader.cs#L359
                case "#~":
                    if (this.tableStream != null)
                    {
                        goto sectionExists;
                    }
                    this.tableStream = new CliMetadataTableStreamAndHeader(currentHeader);
                    this.ScanAndReadSection(sourceImage, tableStream, sdReader => this.tableStream.Read(sdReader, this));
                    break;
                }
                continue;
sectionExists:
                throw new BadImageFormatException(string.Format("Duplicate {0} section encountered.", currentHeader.Name));
            }
            if (this.tableStream == null)
            {
                throw new BadImageFormatException("#~ or #- stream not present in image.");
            }
        }
Ejemplo n.º 6
0
        internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ByteBuffer versionInfoData, byte[] unmanagedResources, int entryPointToken)
        {
            moduleBuilder.FixupMethodBodyTokens();

            moduleBuilder.ModuleTable.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleBuilder.Guids.Add(moduleBuilder.ModuleVersionId), 0, 0);

            if (moduleBuilder.UserStrings.IsEmpty)
            {
                // for compat with Ref.Emit, if there aren't any user strings, we add one
                moduleBuilder.UserStrings.Add(" ");
            }

            using (FileStream fs = new FileStream(moduleBuilder.FullyQualifiedName, FileMode.Create))
            {
                PEWriter writer = new PEWriter(fs);
                switch (imageFileMachine)
                {
                case ImageFileMachine.I386:
                    writer.Headers.FileHeader.Machine          = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386;
                    writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE;
                    break;

                case ImageFileMachine.AMD64:
                    writer.Headers.FileHeader.Machine                = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64;
                    writer.Headers.FileHeader.Characteristics       |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
                    writer.Headers.FileHeader.SizeOfOptionalHeader   = 0xF0;
                    writer.Headers.OptionalHeader.Magic              = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
                    writer.Headers.OptionalHeader.SizeOfStackReserve = 0x400000;
                    writer.Headers.OptionalHeader.SizeOfStackCommit  = 0x4000;
                    writer.Headers.OptionalHeader.SizeOfHeapCommit   = 0x2000;
                    break;

                case ImageFileMachine.IA64:
                    writer.Headers.FileHeader.Machine                = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64;
                    writer.Headers.FileHeader.Characteristics       |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
                    writer.Headers.FileHeader.SizeOfOptionalHeader   = 0xF0;
                    writer.Headers.OptionalHeader.Magic              = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
                    writer.Headers.OptionalHeader.SizeOfStackReserve = 0x400000;
                    writer.Headers.OptionalHeader.SizeOfStackCommit  = 0x4000;
                    writer.Headers.OptionalHeader.SizeOfHeapCommit   = 0x2000;
                    break;

                default:
                    throw new ArgumentOutOfRangeException("imageFileMachine");
                }
                if (fileKind == PEFileKinds.Dll)
                {
                    writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_DLL;
                }

                switch (fileKind)
                {
                case PEFileKinds.WindowApplication:
                    writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_GUI;
                    break;

                default:
                    writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_CUI;
                    break;
                }
                writer.Headers.OptionalHeader.DllCharacteristics =
                    IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE |
                    IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NO_SEH |
                    IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NX_COMPAT |
                    IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE;

                CliHeader cliHeader = new CliHeader();
                cliHeader.Cb = 0x48;
                cliHeader.MajorRuntimeVersion = 2;
                cliHeader.MinorRuntimeVersion = moduleBuilder.MDStreamVersion < 0x20000 ? (ushort)0 : (ushort)5;
                if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0)
                {
                    cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_ILONLY;
                }
                if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0)
                {
                    cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED;
                }
                if (keyPair != null)
                {
                    cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_STRONGNAMESIGNED;
                }
                if (moduleBuilder.IsPseudoToken(entryPointToken))
                {
                    entryPointToken = moduleBuilder.ResolvePseudoToken(entryPointToken);
                }
                cliHeader.EntryPointToken = (uint)entryPointToken;

                moduleBuilder.Strings.Freeze();
                moduleBuilder.UserStrings.Freeze();
                moduleBuilder.Guids.Freeze();
                moduleBuilder.Blobs.Freeze();
                MetadataWriter mw = new MetadataWriter(moduleBuilder, fs);
                moduleBuilder.Tables.Freeze(mw);
                TextSection     code      = new TextSection(writer, cliHeader, moduleBuilder, publicKey != null);
                ResourceSection resources = new ResourceSection(versionInfoData, unmanagedResources);

                // Import Directory
                writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA;
                writer.Headers.OptionalHeader.DataDirectory[1].Size           = code.ImportDirectoryLength;

                // Import Address Table Directory
                writer.Headers.OptionalHeader.DataDirectory[12].VirtualAddress = code.ImportAddressTableRVA;
                writer.Headers.OptionalHeader.DataDirectory[12].Size           = code.ImportAddressTableLength;

                // COM Descriptor Directory
                writer.Headers.OptionalHeader.DataDirectory[14].VirtualAddress = code.ComDescriptorRVA;
                writer.Headers.OptionalHeader.DataDirectory[14].Size           = code.ComDescriptorLength;

                // Debug Directory
                if (code.DebugDirectoryLength != 0)
                {
                    writer.Headers.OptionalHeader.DataDirectory[6].VirtualAddress = code.DebugDirectoryRVA;
                    writer.Headers.OptionalHeader.DataDirectory[6].Size           = code.DebugDirectoryLength;
                }

                writer.Headers.FileHeader.NumberOfSections = 2;

                if (moduleBuilder.initializedData.Length != 0)
                {
                    writer.Headers.FileHeader.NumberOfSections++;
                }

                if (resources.Length != 0)
                {
                    writer.Headers.FileHeader.NumberOfSections++;
                }

                SectionHeader text = new SectionHeader();
                text.Name             = ".text";
                text.VirtualAddress   = code.BaseRVA;
                text.VirtualSize      = (uint)code.Length;
                text.PointerToRawData = code.PointerToRawData;
                text.SizeOfRawData    = writer.ToFileAlignment((uint)code.Length);
                text.Characteristics  = SectionHeader.IMAGE_SCN_CNT_CODE | SectionHeader.IMAGE_SCN_MEM_EXECUTE | SectionHeader.IMAGE_SCN_MEM_READ;

                SectionHeader sdata = new SectionHeader();
                sdata.Name             = ".sdata";
                sdata.VirtualAddress   = text.VirtualAddress + writer.ToSectionAlignment(text.VirtualSize);
                sdata.VirtualSize      = (uint)moduleBuilder.initializedData.Length;
                sdata.PointerToRawData = text.PointerToRawData + text.SizeOfRawData;
                sdata.SizeOfRawData    = writer.ToFileAlignment((uint)moduleBuilder.initializedData.Length);
                sdata.Characteristics  = SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_MEM_WRITE;

                SectionHeader rsrc = new SectionHeader();
                rsrc.Name             = ".rsrc";
                rsrc.VirtualAddress   = sdata.VirtualAddress + writer.ToSectionAlignment(sdata.VirtualSize);
                rsrc.PointerToRawData = sdata.PointerToRawData + sdata.SizeOfRawData;
                rsrc.VirtualSize      = (uint)resources.Length;
                rsrc.SizeOfRawData    = writer.ToFileAlignment(rsrc.VirtualSize);
                rsrc.Characteristics  = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA;

                if (rsrc.SizeOfRawData != 0)
                {
                    // Resource Directory
                    writer.Headers.OptionalHeader.DataDirectory[2].VirtualAddress = rsrc.VirtualAddress;
                    writer.Headers.OptionalHeader.DataDirectory[2].Size           = rsrc.VirtualSize;
                }

                SectionHeader reloc = new SectionHeader();
                reloc.Name             = ".reloc";
                reloc.VirtualAddress   = rsrc.VirtualAddress + writer.ToSectionAlignment(rsrc.VirtualSize);
                reloc.VirtualSize      = 12;
                reloc.PointerToRawData = rsrc.PointerToRawData + rsrc.SizeOfRawData;
                reloc.SizeOfRawData    = writer.ToFileAlignment(reloc.VirtualSize);
                reloc.Characteristics  = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_DISCARDABLE;

                // Base Relocation Directory
                writer.Headers.OptionalHeader.DataDirectory[5].VirtualAddress = reloc.VirtualAddress;
                writer.Headers.OptionalHeader.DataDirectory[5].Size           = reloc.VirtualSize;

                writer.Headers.OptionalHeader.SizeOfCode              = text.SizeOfRawData;
                writer.Headers.OptionalHeader.SizeOfInitializedData   = sdata.SizeOfRawData + rsrc.SizeOfRawData + reloc.SizeOfRawData;
                writer.Headers.OptionalHeader.SizeOfUninitializedData = 0;
                writer.Headers.OptionalHeader.SizeOfImage             = reloc.VirtualAddress + writer.ToSectionAlignment(reloc.VirtualSize);
                writer.Headers.OptionalHeader.SizeOfHeaders           = text.PointerToRawData;
                writer.Headers.OptionalHeader.BaseOfCode              = code.BaseRVA;
                writer.Headers.OptionalHeader.BaseOfData              = sdata.VirtualAddress;
                writer.Headers.OptionalHeader.ImageBase = (ulong)moduleBuilder.__ImageBase;

                if (imageFileMachine == ImageFileMachine.IA64)
                {
                    // apparently for IA64 AddressOfEntryPoint points to the address of the entry point
                    // (i.e. there is an additional layer of indirection), so we add the offset to the pointer
                    writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + 0x20;
                }
                else
                {
                    writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA;
                }

                writer.WritePEHeaders();
                writer.WriteSectionHeader(text);
                if (sdata.SizeOfRawData != 0)
                {
                    writer.WriteSectionHeader(sdata);
                }
                if (rsrc.SizeOfRawData != 0)
                {
                    writer.WriteSectionHeader(rsrc);
                }
                writer.WriteSectionHeader(reloc);

                fs.Seek(text.PointerToRawData, SeekOrigin.Begin);
                code.Write(mw, (int)sdata.VirtualAddress);

                fs.Seek(sdata.PointerToRawData, SeekOrigin.Begin);
                mw.Write(moduleBuilder.initializedData);

                if (rsrc.SizeOfRawData != 0)
                {
                    fs.Seek(rsrc.PointerToRawData, SeekOrigin.Begin);
                    resources.Write(mw, rsrc.VirtualAddress);
                }

                fs.Seek(reloc.PointerToRawData, SeekOrigin.Begin);
                // .reloc section
                uint relocAddress = code.StartupStubRVA;
                switch (imageFileMachine)
                {
                case ImageFileMachine.I386:
                case ImageFileMachine.AMD64:
                    relocAddress += 2;
                    break;

                case ImageFileMachine.IA64:
                    relocAddress += 0x20;
                    break;
                }
                uint pageRVA = relocAddress & ~0xFFFU;
                mw.Write(pageRVA);                      // PageRVA
                mw.Write(0x000C);                       // Block Size
                if (imageFileMachine == ImageFileMachine.I386)
                {
                    mw.Write(0x3000 + relocAddress - pageRVA);                                                  // Type / Offset
                }
                else if (imageFileMachine == ImageFileMachine.AMD64)
                {
                    mw.Write(0xA000 + relocAddress - pageRVA);                                                  // Type / Offset
                }
                else if (imageFileMachine == ImageFileMachine.IA64)
                {
                    // on IA64 the StartupStubRVA is 16 byte aligned, so these two addresses won't cross a page boundary
                    mw.Write((short)(0xA000 + relocAddress - pageRVA));                         // Type / Offset
                    mw.Write((short)(0xA000 + relocAddress - pageRVA + 8));                     // Type / Offset
                }

                // file alignment
                mw.Write(new byte[writer.Headers.OptionalHeader.FileAlignment - reloc.VirtualSize]);

                // do the strong naming
                if (keyPair != null)
                {
                    StrongName(fs, keyPair, writer.HeaderSize, text.PointerToRawData, code.StrongNameSignatureRVA - text.VirtualAddress + text.PointerToRawData, code.StrongNameSignatureLength);
                }
            }

            if (moduleBuilder.symbolWriter != null)
            {
                moduleBuilder.WriteSymbolTokenMap();
                moduleBuilder.symbolWriter.Close();
            }
        }