/Mono.Cecil/Mono.Cecil.PE/ImageWriter.cs
http://github.com/icsharpcode/ILSpy · C# · 824 lines · 624 code · 145 blank · 55 comment · 71 complexity · e70d2b7260d08936e17502d92a4c24e2 MD5 · raw file
- //
- // ImageWriter.cs
- //
- // Author:
- // Jb Evain (jbevain@gmail.com)
- //
- // Copyright (c) 2008 - 2011 Jb Evain
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.IO;
- #if !READ_ONLY
- using Mono.Cecil.Cil;
- using Mono.Cecil.Metadata;
- using RVA = System.UInt32;
- namespace Mono.Cecil.PE {
- sealed class ImageWriter : BinaryStreamWriter {
- readonly ModuleDefinition module;
- readonly MetadataBuilder metadata;
- readonly TextMap text_map;
- ImageDebugDirectory debug_directory;
- byte [] debug_data;
- ByteBuffer win32_resources;
- const uint pe_header_size = 0x178u;
- const uint section_header_size = 0x28u;
- const uint file_alignment = 0x200;
- const uint section_alignment = 0x2000;
- const ulong image_base = 0x00400000;
- internal const RVA text_rva = 0x2000;
- readonly bool pe64;
- readonly uint time_stamp;
- internal Section text;
- internal Section rsrc;
- internal Section reloc;
- ushort sections;
- ImageWriter (ModuleDefinition module, MetadataBuilder metadata, Stream stream)
- : base (stream)
- {
- this.module = module;
- this.metadata = metadata;
- this.pe64 = module.Architecture != TargetArchitecture.I386;
- this.GetDebugHeader ();
- this.GetWin32Resources ();
- this.text_map = BuildTextMap ();
- this.sections = (ushort) (pe64 ? 1 : 2); // text + reloc
- this.time_stamp = (uint) DateTime.UtcNow.Subtract (new DateTime (1970, 1, 1)).TotalSeconds;
- }
- void GetDebugHeader ()
- {
- var symbol_writer = metadata.symbol_writer;
- if (symbol_writer == null)
- return;
- if (!symbol_writer.GetDebugHeader (out debug_directory, out debug_data))
- debug_data = Empty<byte>.Array;
- }
- void GetWin32Resources ()
- {
- var rsrc = GetImageResourceSection ();
- if (rsrc == null)
- return;
- var raw_resources = new byte [rsrc.Data.Length];
- Buffer.BlockCopy (rsrc.Data, 0, raw_resources, 0, rsrc.Data.Length);
- win32_resources = new ByteBuffer (raw_resources);
- }
- Section GetImageResourceSection ()
- {
- if (!module.HasImage)
- return null;
- const string rsrc_section = ".rsrc";
- return module.Image.GetSection (rsrc_section);
- }
- public static ImageWriter CreateWriter (ModuleDefinition module, MetadataBuilder metadata, Stream stream)
- {
- var writer = new ImageWriter (module, metadata, stream);
- writer.BuildSections ();
- return writer;
- }
- void BuildSections ()
- {
- var has_win32_resources = win32_resources != null;
- if (has_win32_resources)
- sections++;
- text = CreateSection (".text", text_map.GetLength (), null);
- var previous = text;
- if (has_win32_resources) {
- rsrc = CreateSection (".rsrc", (uint) win32_resources.length, previous);
- PatchWin32Resources (win32_resources);
- previous = rsrc;
- }
- if (!pe64)
- reloc = CreateSection (".reloc", 12u, previous);
- }
- Section CreateSection (string name, uint size, Section previous)
- {
- return new Section {
- Name = name,
- VirtualAddress = previous != null
- ? previous.VirtualAddress + Align (previous.VirtualSize, section_alignment)
- : text_rva,
- VirtualSize = size,
- PointerToRawData = previous != null
- ? previous.PointerToRawData + previous.SizeOfRawData
- : Align (GetHeaderSize (), file_alignment),
- SizeOfRawData = Align (size, file_alignment)
- };
- }
- static uint Align (uint value, uint align)
- {
- align--;
- return (value + align) & ~align;
- }
- void WriteDOSHeader ()
- {
- Write (new byte [] {
- // dos header start
- 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00,
- 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff,
- 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- // lfanew
- 0x80, 0x00, 0x00, 0x00,
- // dos header end
- 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09,
- 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21,
- 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72,
- 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x63,
- 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62,
- 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69,
- 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d,
- 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
- 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00
- });
- }
- void WritePEFileHeader ()
- {
- WriteUInt32 (0x00004550); // Magic
- WriteUInt16 (GetMachine ()); // Machine
- WriteUInt16 (sections); // NumberOfSections
- WriteUInt32 (time_stamp);
- WriteUInt32 (0); // PointerToSymbolTable
- WriteUInt32 (0); // NumberOfSymbols
- WriteUInt16 ((ushort) (!pe64 ? 0xe0 : 0xf0)); // SizeOfOptionalHeader
- // ExecutableImage | (pe64 ? 32BitsMachine : LargeAddressAware)
- var characteristics = (ushort) (0x0002 | (!pe64 ? 0x0100 : 0x0020));
- if (module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule)
- characteristics |= 0x2000;
- WriteUInt16 (characteristics); // Characteristics
- }
- ushort GetMachine ()
- {
- switch (module.Architecture) {
- case TargetArchitecture.I386:
- return 0x014c;
- case TargetArchitecture.AMD64:
- return 0x8664;
- case TargetArchitecture.IA64:
- return 0x0200;
- }
- throw new NotSupportedException ();
- }
- Section LastSection ()
- {
- if (reloc != null)
- return reloc;
- if (rsrc != null)
- return rsrc;
- return text;
- }
- void WriteOptionalHeaders ()
- {
- WriteUInt16 ((ushort) (!pe64 ? 0x10b : 0x20b)); // Magic
- WriteByte (8); // LMajor
- WriteByte (0); // LMinor
- WriteUInt32 (text.SizeOfRawData); // CodeSize
- WriteUInt32 ((reloc != null ? reloc.SizeOfRawData : 0)
- + (rsrc != null ? rsrc.SizeOfRawData : 0)); // InitializedDataSize
- WriteUInt32 (0); // UninitializedDataSize
- var startub_stub = text_map.GetRange (TextSegment.StartupStub);
- WriteUInt32 (startub_stub.Length > 0 ? startub_stub.Start : 0); // EntryPointRVA
- WriteUInt32 (text_rva); // BaseOfCode
- if (!pe64) {
- WriteUInt32 (0); // BaseOfData
- WriteUInt32 ((uint) image_base); // ImageBase
- } else {
- WriteUInt64 (image_base); // ImageBase
- }
- WriteUInt32 (section_alignment); // SectionAlignment
- WriteUInt32 (file_alignment); // FileAlignment
- WriteUInt16 (4); // OSMajor
- WriteUInt16 (0); // OSMinor
- WriteUInt16 (0); // UserMajor
- WriteUInt16 (0); // UserMinor
- WriteUInt16 (4); // SubSysMajor
- WriteUInt16 (0); // SubSysMinor
- WriteUInt32 (0); // Reserved
- var last_section = LastSection();
- WriteUInt32 (last_section.VirtualAddress + Align (last_section.VirtualSize, section_alignment)); // ImageSize
- WriteUInt32 (text.PointerToRawData); // HeaderSize
- WriteUInt32 (0); // Checksum
- WriteUInt16 (GetSubSystem ()); // SubSystem
- WriteUInt16 ((ushort) module.Characteristics); // DLLFlags
- const ulong stack_reserve = 0x100000;
- const ulong stack_commit = 0x1000;
- const ulong heap_reserve = 0x100000;
- const ulong heap_commit = 0x1000;
- if (!pe64) {
- WriteUInt32 ((uint) stack_reserve);
- WriteUInt32 ((uint) stack_commit);
- WriteUInt32 ((uint) heap_reserve);
- WriteUInt32 ((uint) heap_commit);
- } else {
- WriteUInt64 (stack_reserve);
- WriteUInt64 (stack_commit);
- WriteUInt64 (heap_reserve);
- WriteUInt64 (heap_commit);
- }
- WriteUInt32 (0); // LoaderFlags
- WriteUInt32 (16); // NumberOfDataDir
- WriteZeroDataDirectory (); // ExportTable
- WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportDirectory)); // ImportTable
- if (rsrc != null) { // ResourceTable
- WriteUInt32 (rsrc.VirtualAddress);
- WriteUInt32 (rsrc.VirtualSize);
- } else
- WriteZeroDataDirectory ();
- WriteZeroDataDirectory (); // ExceptionTable
- WriteZeroDataDirectory (); // CertificateTable
- WriteUInt32 (reloc != null ? reloc.VirtualAddress : 0); // BaseRelocationTable
- WriteUInt32 (reloc != null ? reloc.VirtualSize : 0);
- if (text_map.GetLength (TextSegment.DebugDirectory) > 0) {
- WriteUInt32 (text_map.GetRVA (TextSegment.DebugDirectory));
- WriteUInt32 (28u);
- } else
- WriteZeroDataDirectory ();
- WriteZeroDataDirectory (); // Copyright
- WriteZeroDataDirectory (); // GlobalPtr
- WriteZeroDataDirectory (); // TLSTable
- WriteZeroDataDirectory (); // LoadConfigTable
- WriteZeroDataDirectory (); // BoundImport
- WriteDataDirectory (text_map.GetDataDirectory (TextSegment.ImportAddressTable)); // IAT
- WriteZeroDataDirectory (); // DelayImportDesc
- WriteDataDirectory (text_map.GetDataDirectory (TextSegment.CLIHeader)); // CLIHeader
- WriteZeroDataDirectory (); // Reserved
- }
- void WriteZeroDataDirectory ()
- {
- WriteUInt32 (0);
- WriteUInt32 (0);
- }
- ushort GetSubSystem ()
- {
- switch (module.Kind) {
- case ModuleKind.Console:
- case ModuleKind.Dll:
- case ModuleKind.NetModule:
- return 0x3;
- case ModuleKind.Windows:
- return 0x2;
- default:
- throw new ArgumentOutOfRangeException ();
- }
- }
- void WriteSectionHeaders ()
- {
- WriteSection (text, 0x60000020);
- if (rsrc != null)
- WriteSection (rsrc, 0x40000040);
- if (reloc != null)
- WriteSection (reloc, 0x42000040);
- }
- void WriteSection (Section section, uint characteristics)
- {
- var name = new byte [8];
- var sect_name = section.Name;
- for (int i = 0; i < sect_name.Length; i++)
- name [i] = (byte) sect_name [i];
- WriteBytes (name);
- WriteUInt32 (section.VirtualSize);
- WriteUInt32 (section.VirtualAddress);
- WriteUInt32 (section.SizeOfRawData);
- WriteUInt32 (section.PointerToRawData);
- WriteUInt32 (0); // PointerToRelocations
- WriteUInt32 (0); // PointerToLineNumbers
- WriteUInt16 (0); // NumberOfRelocations
- WriteUInt16 (0); // NumberOfLineNumbers
- WriteUInt32 (characteristics);
- }
- void MoveTo (uint pointer)
- {
- BaseStream.Seek (pointer, SeekOrigin.Begin);
- }
- void MoveToRVA (Section section, RVA rva)
- {
- BaseStream.Seek (section.PointerToRawData + rva - section.VirtualAddress, SeekOrigin.Begin);
- }
- void MoveToRVA (TextSegment segment)
- {
- MoveToRVA (text, text_map.GetRVA (segment));
- }
- void WriteRVA (RVA rva)
- {
- if (!pe64)
- WriteUInt32 (rva);
- else
- WriteUInt64 (rva);
- }
- void WriteText ()
- {
- MoveTo (text.PointerToRawData);
- // ImportAddressTable
- if (!pe64) {
- WriteRVA (text_map.GetRVA (TextSegment.ImportHintNameTable));
- WriteRVA (0);
- }
- // CLIHeader
- WriteUInt32 (0x48);
- WriteUInt16 (2);
- WriteUInt16 ((ushort) ((module.Runtime <= TargetRuntime.Net_1_1) ? 0 : 5));
- WriteUInt32 (text_map.GetRVA (TextSegment.MetadataHeader));
- WriteUInt32 (GetMetadataLength ());
- WriteUInt32 ((uint) module.Attributes);
- WriteUInt32 (metadata.entry_point.ToUInt32 ());
- WriteDataDirectory (text_map.GetDataDirectory (TextSegment.Resources));
- WriteDataDirectory (text_map.GetDataDirectory (TextSegment.StrongNameSignature));
- WriteZeroDataDirectory (); // CodeManagerTable
- WriteZeroDataDirectory (); // VTableFixups
- WriteZeroDataDirectory (); // ExportAddressTableJumps
- WriteZeroDataDirectory (); // ManagedNativeHeader
- // Code
- MoveToRVA (TextSegment.Code);
- WriteBuffer (metadata.code);
- // Resources
- MoveToRVA (TextSegment.Resources);
- WriteBuffer (metadata.resources);
- // Data
- if (metadata.data.length > 0) {
- MoveToRVA (TextSegment.Data);
- WriteBuffer (metadata.data);
- }
- // StrongNameSignature
- // stays blank
- // MetadataHeader
- MoveToRVA (TextSegment.MetadataHeader);
- WriteMetadataHeader ();
- WriteMetadata ();
- // DebugDirectory
- if (text_map.GetLength (TextSegment.DebugDirectory) > 0) {
- MoveToRVA (TextSegment.DebugDirectory);
- WriteDebugDirectory ();
- }
- if (pe64)
- return;
- // ImportDirectory
- MoveToRVA (TextSegment.ImportDirectory);
- WriteImportDirectory ();
- // StartupStub
- MoveToRVA (TextSegment.StartupStub);
- WriteStartupStub ();
- }
- uint GetMetadataLength ()
- {
- return text_map.GetRVA (TextSegment.DebugDirectory) - text_map.GetRVA (TextSegment.MetadataHeader);
- }
- void WriteMetadataHeader ()
- {
- WriteUInt32 (0x424a5342); // Signature
- WriteUInt16 (1); // MajorVersion
- WriteUInt16 (1); // MinorVersion
- WriteUInt32 (0); // Reserved
- var version = GetZeroTerminatedString (GetVersion ());
- WriteUInt32 ((uint) version.Length);
- WriteBytes (version);
- WriteUInt16 (0); // Flags
- WriteUInt16 (GetStreamCount ());
- uint offset = text_map.GetRVA (TextSegment.TableHeap) - text_map.GetRVA (TextSegment.MetadataHeader);
- WriteStreamHeader (ref offset, TextSegment.TableHeap, "#~");
- WriteStreamHeader (ref offset, TextSegment.StringHeap, "#Strings");
- WriteStreamHeader (ref offset, TextSegment.UserStringHeap, "#US");
- WriteStreamHeader (ref offset, TextSegment.GuidHeap, "#GUID");
- WriteStreamHeader (ref offset, TextSegment.BlobHeap, "#Blob");
- }
- string GetVersion ()
- {
- switch (module.Runtime) {
- case TargetRuntime.Net_1_0:
- return "v1.0.3705";
- case TargetRuntime.Net_1_1:
- return "v1.1.4322";
- case TargetRuntime.Net_2_0:
- return "v2.0.50727";
- case TargetRuntime.Net_4_0:
- default:
- return "v4.0.30319";
- }
- }
- ushort GetStreamCount ()
- {
- return (ushort) (
- 1 // #~
- + 1 // #Strings
- + (metadata.user_string_heap.IsEmpty ? 0 : 1) // #US
- + 1 // GUID
- + (metadata.blob_heap.IsEmpty ? 0 : 1)); // #Blob
- }
- void WriteStreamHeader (ref uint offset, TextSegment heap, string name)
- {
- var length = (uint) text_map.GetLength (heap);
- if (length == 0)
- return;
- WriteUInt32 (offset);
- WriteUInt32 (length);
- WriteBytes (GetZeroTerminatedString (name));
- offset += length;
- }
- static byte [] GetZeroTerminatedString (string @string)
- {
- return GetString (@string, (@string.Length + 1 + 3) & ~3);
- }
- static byte [] GetSimpleString (string @string)
- {
- return GetString (@string, @string.Length);
- }
- static byte [] GetString (string @string, int length)
- {
- var bytes = new byte [length];
- for (int i = 0; i < @string.Length; i++)
- bytes [i] = (byte) @string [i];
- return bytes;
- }
- void WriteMetadata ()
- {
- WriteHeap (TextSegment.TableHeap, metadata.table_heap);
- WriteHeap (TextSegment.StringHeap, metadata.string_heap);
- WriteHeap (TextSegment.UserStringHeap, metadata.user_string_heap);
- WriteGuidHeap ();
- WriteHeap (TextSegment.BlobHeap, metadata.blob_heap);
- }
- void WriteHeap (TextSegment heap, HeapBuffer buffer)
- {
- if (buffer.IsEmpty)
- return;
- MoveToRVA (heap);
- WriteBuffer (buffer);
- }
- void WriteGuidHeap ()
- {
- MoveToRVA (TextSegment.GuidHeap);
- WriteBytes (module.Mvid.ToByteArray ());
- }
- void WriteDebugDirectory ()
- {
- WriteInt32 (debug_directory.Characteristics);
- WriteUInt32 (time_stamp);
- WriteInt16 (debug_directory.MajorVersion);
- WriteInt16 (debug_directory.MinorVersion);
- WriteInt32 (debug_directory.Type);
- WriteInt32 (debug_directory.SizeOfData);
- WriteInt32 (debug_directory.AddressOfRawData);
- WriteInt32 ((int) BaseStream.Position + 4);
- WriteBytes (debug_data);
- }
- void WriteImportDirectory ()
- {
- WriteUInt32 (text_map.GetRVA (TextSegment.ImportDirectory) + 40); // ImportLookupTable
- WriteUInt32 (0); // DateTimeStamp
- WriteUInt32 (0); // ForwarderChain
- WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable) + 14);
- WriteUInt32 (text_map.GetRVA (TextSegment.ImportAddressTable));
- Advance (20);
- // ImportLookupTable
- WriteUInt32 (text_map.GetRVA (TextSegment.ImportHintNameTable));
- // ImportHintNameTable
- MoveToRVA (TextSegment.ImportHintNameTable);
- WriteUInt16 (0); // Hint
- WriteBytes (GetRuntimeMain ());
- WriteByte (0);
- WriteBytes (GetSimpleString ("mscoree.dll"));
- WriteUInt16 (0);
- }
- byte [] GetRuntimeMain ()
- {
- return module.Kind == ModuleKind.Dll || module.Kind == ModuleKind.NetModule
- ? GetSimpleString ("_CorDllMain")
- : GetSimpleString ("_CorExeMain");
- }
- void WriteStartupStub ()
- {
- switch (module.Architecture) {
- case TargetArchitecture.I386:
- WriteUInt16 (0x25ff);
- WriteUInt32 ((uint) image_base + text_map.GetRVA (TextSegment.ImportAddressTable));
- return;
- default:
- throw new NotSupportedException ();
- }
- }
- void WriteRsrc ()
- {
- MoveTo (rsrc.PointerToRawData);
- WriteBuffer (win32_resources);
- }
- void WriteReloc ()
- {
- MoveTo (reloc.PointerToRawData);
- var reloc_rva = text_map.GetRVA (TextSegment.StartupStub);
- reloc_rva += module.Architecture == TargetArchitecture.IA64 ? 0x20u : 2;
- var page_rva = reloc_rva & ~0xfffu;
- WriteUInt32 (page_rva); // PageRVA
- WriteUInt32 (0x000c); // Block Size
- switch (module.Architecture) {
- case TargetArchitecture.I386:
- WriteUInt32 (0x3000 + reloc_rva - page_rva);
- break;
- default:
- throw new NotSupportedException();
- }
- WriteBytes (new byte [file_alignment - reloc.VirtualSize]);
- }
- public void WriteImage ()
- {
- WriteDOSHeader ();
- WritePEFileHeader ();
- WriteOptionalHeaders ();
- WriteSectionHeaders ();
- WriteText ();
- if (rsrc != null)
- WriteRsrc ();
- if (reloc != null)
- WriteReloc ();
- }
- TextMap BuildTextMap ()
- {
- var map = metadata.text_map;
- map.AddMap (TextSegment.Code, metadata.code.length, !pe64 ? 4 : 16);
- map.AddMap (TextSegment.Resources, metadata.resources.length, 8);
- map.AddMap (TextSegment.Data, metadata.data.length, 4);
- if (metadata.data.length > 0)
- metadata.table_heap.FixupData (map.GetRVA (TextSegment.Data));
- map.AddMap (TextSegment.StrongNameSignature, GetStrongNameLength (), 4);
- map.AddMap (TextSegment.MetadataHeader, GetMetadataHeaderLength ());
- map.AddMap (TextSegment.TableHeap, metadata.table_heap.length, 4);
- map.AddMap (TextSegment.StringHeap, metadata.string_heap.length, 4);
- map.AddMap (TextSegment.UserStringHeap, metadata.user_string_heap.IsEmpty ? 0 : metadata.user_string_heap.length, 4);
- map.AddMap (TextSegment.GuidHeap, 16);
- map.AddMap (TextSegment.BlobHeap, metadata.blob_heap.IsEmpty ? 0 : metadata.blob_heap.length, 4);
- int debug_dir_len = 0;
- if (!debug_data.IsNullOrEmpty ()) {
- const int debug_dir_header_len = 28;
- debug_directory.AddressOfRawData = (int) map.GetNextRVA (TextSegment.BlobHeap) + debug_dir_header_len;
- debug_dir_len = debug_data.Length + debug_dir_header_len;
- }
- map.AddMap (TextSegment.DebugDirectory, debug_dir_len, 4);
- if (pe64) {
- var start = map.GetNextRVA (TextSegment.DebugDirectory);
- map.AddMap (TextSegment.ImportDirectory, new Range (start, 0));
- map.AddMap (TextSegment.ImportHintNameTable, new Range (start, 0));
- map.AddMap (TextSegment.StartupStub, new Range (start, 0));
- return map;
- }
- RVA import_dir_rva = map.GetNextRVA (TextSegment.DebugDirectory);
- RVA import_hnt_rva = import_dir_rva + 48u;
- import_hnt_rva = (import_hnt_rva + 15u) & ~15u;
- uint import_dir_len = (import_hnt_rva - import_dir_rva) + 27u;
- RVA startup_stub_rva = import_dir_rva + import_dir_len;
- startup_stub_rva = module.Architecture == TargetArchitecture.IA64
- ? (startup_stub_rva + 15u) & ~15u
- : 2 + ((startup_stub_rva + 3u) & ~3u);
- map.AddMap (TextSegment.ImportDirectory, new Range (import_dir_rva, import_dir_len));
- map.AddMap (TextSegment.ImportHintNameTable, new Range (import_hnt_rva, 0));
- map.AddMap (TextSegment.StartupStub, new Range (startup_stub_rva, GetStartupStubLength ()));
- return map;
- }
- uint GetStartupStubLength ()
- {
- switch (module.Architecture) {
- case TargetArchitecture.I386:
- return 6;
- default:
- throw new NotSupportedException ();
- }
- }
- int GetMetadataHeaderLength ()
- {
- return
- // MetadataHeader
- 40
- // #~ header
- + 12
- // #Strings header
- + 20
- // #US header
- + (metadata.user_string_heap.IsEmpty ? 0 : 12)
- // #GUID header
- + 16
- // #Blob header
- + (metadata.blob_heap.IsEmpty ? 0 : 16);
- }
- int GetStrongNameLength ()
- {
- if (module.Assembly == null)
- return 0;
- var public_key = module.Assembly.Name.PublicKey;
- if (public_key.IsNullOrEmpty ())
- return 0;
- // in fx 2.0 the key may be from 384 to 16384 bits
- // so we must calculate the signature size based on
- // the size of the public key (minus the 32 byte header)
- int size = public_key.Length;
- if (size > 32)
- return size - 32;
- // note: size == 16 for the ECMA "key" which is replaced
- // by the runtime with a 1024 bits key (128 bytes)
- return 128; // default strongname signature size
- }
- public DataDirectory GetStrongNameSignatureDirectory ()
- {
- return text_map.GetDataDirectory (TextSegment.StrongNameSignature);
- }
- public uint GetHeaderSize ()
- {
- return pe_header_size + (sections * section_header_size);
- }
- void PatchWin32Resources (ByteBuffer resources)
- {
- PatchResourceDirectoryTable (resources);
- }
- void PatchResourceDirectoryTable (ByteBuffer resources)
- {
- resources.Advance (12);
- var entries = resources.ReadUInt16 () + resources.ReadUInt16 ();
- for (int i = 0; i < entries; i++)
- PatchResourceDirectoryEntry (resources);
- }
- void PatchResourceDirectoryEntry (ByteBuffer resources)
- {
- resources.Advance (4);
- var child = resources.ReadUInt32 ();
- var position = resources.position;
- resources.position = (int) child & 0x7fffffff;
- if ((child & 0x80000000) != 0)
- PatchResourceDirectoryTable (resources);
- else
- PatchResourceDataEntry (resources);
- resources.position = position;
- }
- void PatchResourceDataEntry (ByteBuffer resources)
- {
- var old_rsrc = GetImageResourceSection ();
- var rva = resources.ReadUInt32 ();
- resources.position -= 4;
- resources.WriteUInt32 (rva - old_rsrc.VirtualAddress + rsrc.VirtualAddress);
- }
- }
- }
- #endif