internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken, Stream stream) { if (stream == null) { string fileName = moduleBuilder.FullyQualifiedName; bool mono = System.Type.GetType("Mono.Runtime") != null; if (mono) { try { // Mono mmaps the file, so unlink the previous version since it may be in use File.Delete(fileName); } catch { } } using (FileStream fs = new FileStream(fileName, FileMode.Create)) { WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, fs); } // if we're running on Mono, mark the module as executable by using a Mono private API extension if (mono) { File.SetAttributes(fileName, (FileAttributes)(unchecked ((int)0x80000000))); } } else { WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, stream); } }
internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken, Stream stream) { if (stream == null) { string fileName = moduleBuilder.FullyQualifiedName; bool mono = System.Type.GetType("Mono.Runtime") != null; if (mono) { try { // Mono mmaps the file, so unlink the previous version since it may be in use File.Delete(fileName); } catch { } } using (FileStream fs = new FileStream(fileName, FileMode.Create)) { WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, fs); } // if we're running on Mono, mark the module as executable by using a Mono private API extension if (mono) { File.SetAttributes(fileName, (FileAttributes)(unchecked((int)0x80000000))); } } else { WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, stream); } }
internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken, Stream stream) { if (stream == null) { using (FileStream fs = new FileStream(moduleBuilder.FullyQualifiedName, FileMode.Create)) { WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, fs); } } else { WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, stream); } }
internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken, Stream stream) { if (stream == null) { using (FileStream fs = new FileStream(moduleBuilder.FullyQualifiedName, FileMode.Create)) { WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, fs); } // if we're running on Mono, mark the module as executable by using a Mono private API extension if (System.Type.GetType("Mono.Runtime") != null) { File.SetAttributes(moduleBuilder.FullyQualifiedName, (FileAttributes)(unchecked((int)0x80000000))); } } else { WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, stream); } }
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(); } }
internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken) { WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, null); }
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); writer.Headers.OptionalHeader.FileAlignment = (uint)moduleBuilder.__FileAlignment; 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 = (ushort)moduleBuilder.__DllCharacteristics; 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(); } }
internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ResourceSection resources, int entryPointToken) { WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, null); }
public void __DefineUnmanagedResource(byte[] resource) { // The standard .NET DefineUnmanagedResource(byte[]) is useless, because it embeds "resource" (as-is) as the .rsrc section, // but it doesn't set the PE file Resource Directory entry to point to it. That's why we have a renamed version, which behaves // like DefineUnmanagedResource(string). unmanagedResources = new ResourceSection(); unmanagedResources.ExtractResources(resource); }
public void __DefineIconResource(byte[] iconFile) { unmanagedResources = new ResourceSection(); unmanagedResources.AddIcon(iconFile); }
private void SaveImpl(string assemblyFileName, Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) { ModuleBuilder manifestModule = null; foreach (ModuleBuilder moduleBuilder in modules) { moduleBuilder.PopulatePropertyAndEventTables(); if (manifestModule == null && string.Compare(moduleBuilder.fileName, assemblyFileName, StringComparison.OrdinalIgnoreCase) == 0) { manifestModule = moduleBuilder; } } if (manifestModule == null) { manifestModule = DefineDynamicModule("RefEmit_OnDiskManifestModule", assemblyFileName, false); } AssemblyTable.Record assemblyRecord = new AssemblyTable.Record(); assemblyRecord.HashAlgId = (int)hashAlgorithm; assemblyRecord.Name = manifestModule.Strings.Add(name); assemblyRecord.MajorVersion = majorVersion; assemblyRecord.MinorVersion = minorVersion; assemblyRecord.BuildNumber = buildVersion; assemblyRecord.RevisionNumber = revisionVersion; if (publicKey != null) { assemblyRecord.PublicKey = manifestModule.Blobs.Add(ByteBuffer.Wrap(publicKey)); assemblyRecord.Flags = (int)(flags | AssemblyNameFlags.PublicKey); } else { assemblyRecord.Flags = (int)(flags & ~AssemblyNameFlags.PublicKey); } if (culture != null) { assemblyRecord.Culture = manifestModule.Strings.Add(culture); } int token = 0x20000000 + manifestModule.AssemblyTable.AddRecord(assemblyRecord); #pragma warning disable 618 // this values are obsolete, but we already know that so we disable the warning System.Security.Permissions.SecurityAction requestMinimum = System.Security.Permissions.SecurityAction.RequestMinimum; System.Security.Permissions.SecurityAction requestOptional = System.Security.Permissions.SecurityAction.RequestOptional; System.Security.Permissions.SecurityAction requestRefuse = System.Security.Permissions.SecurityAction.RequestRefuse; #pragma warning restore 618 if (requiredPermissions != null) { manifestModule.AddDeclarativeSecurity(token, requestMinimum, requiredPermissions); } if (optionalPermissions != null) { manifestModule.AddDeclarativeSecurity(token, requestOptional, optionalPermissions); } if (refusedPermissions != null) { manifestModule.AddDeclarativeSecurity(token, requestRefuse, refusedPermissions); } if (versionInfo != null) { versionInfo.SetName(GetName()); versionInfo.SetFileName(assemblyFileName); foreach (CustomAttributeBuilder cab in customAttributes) { // .NET doesn't support copying blob custom attributes into the version info if (!cab.HasBlob) { versionInfo.SetAttribute(cab); } } ByteBuffer versionInfoData = new ByteBuffer(512); versionInfo.Write(versionInfoData); if (unmanagedResources == null) { unmanagedResources = new ResourceSection(); } unmanagedResources.AddVersionInfo(versionInfoData); } foreach (CustomAttributeBuilder cab in customAttributes) { // we intentionally don't filter out the version info (pseudo) custom attributes (to be compatible with .NET) manifestModule.SetCustomAttribute(0x20000001, cab); } manifestModule.AddDeclarativeSecurity(0x20000001, declarativeSecurity); foreach (Type type in typeForwarders) { manifestModule.AddTypeForwarder(type); } foreach (ResourceFile resfile in resourceFiles) { int fileToken = AddFile(manifestModule, resfile.FileName, 1 /*ContainsNoMetaData*/); ManifestResourceTable.Record rec = new ManifestResourceTable.Record(); rec.Offset = 0; rec.Flags = (int)resfile.Attributes; rec.Name = manifestModule.Strings.Add(resfile.Name); rec.Implementation = fileToken; manifestModule.ManifestResource.AddRecord(rec); } int entryPointToken = 0; foreach (ModuleBuilder moduleBuilder in modules) { moduleBuilder.FillAssemblyRefTable(); if (moduleBuilder != manifestModule) { int fileToken; if (entryPoint != null && entryPoint.Module == moduleBuilder) { ModuleWriter.WriteModule(null, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, moduleBuilder.unmanagedResources, entryPoint.MetadataToken); entryPointToken = fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/); } else { ModuleWriter.WriteModule(null, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, moduleBuilder.unmanagedResources, 0); fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/); } moduleBuilder.ExportTypes(fileToken, manifestModule); } } foreach (Module module in addedModules) { int fileToken = AddFile(manifestModule, module.FullyQualifiedName, 0 /*ContainsMetaData*/); module.ExportTypes(fileToken, manifestModule); } if (entryPointToken == 0 && entryPoint != null) { entryPointToken = entryPoint.MetadataToken; } // finally, write the manifest module ModuleWriter.WriteModule(keyPair, publicKey, manifestModule, fileKind, portableExecutableKind, imageFileMachine, unmanagedResources ?? manifestModule.unmanagedResources, entryPointToken, streamOrNull); }
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(); } }
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(); } }