private void WriteHeaders(Stream peStream, NtHeader ntHeader, CoffHeader coffHeader, List<SectionHeader> sectionHeaders, out long ntHeaderTimestampPosition) { var writer = PooledBlobBuilder.GetInstance(); // MS-DOS stub (128 bytes) writer.WriteBytes(s_dosHeader); // PE Signature "PE\0\0" writer.WriteUInt32(0x00004550); // COFF Header (20 bytes) writer.WriteUInt16((ushort)coffHeader.Machine); writer.WriteUInt16((ushort)coffHeader.NumberOfSections); ntHeaderTimestampPosition = writer.Position + peStream.Position; writer.WriteUInt32((uint)coffHeader.TimeDateStamp); writer.WriteUInt32((uint)coffHeader.PointerToSymbolTable); writer.WriteUInt32((uint)coffHeader.NumberOfSymbols); writer.WriteUInt16((ushort)(_is32bit ? 224 : 240)); // SizeOfOptionalHeader writer.WriteUInt16((ushort)coffHeader.Characteristics); // PE Headers: writer.WriteUInt16((ushort)(_is32bit ? PEMagic.PE32 : PEMagic.PE32Plus)); // 2 writer.WriteByte(ntHeader.MajorLinkerVersion); // 3 writer.WriteByte(ntHeader.MinorLinkerVersion); // 4 writer.WriteUInt32((uint)ntHeader.SizeOfCode); // 8 writer.WriteUInt32((uint)ntHeader.SizeOfInitializedData); // 12 writer.WriteUInt32((uint)ntHeader.SizeOfUninitializedData); // 16 writer.WriteUInt32((uint)ntHeader.AddressOfEntryPoint); // 20 writer.WriteUInt32((uint)ntHeader.BaseOfCode); // 24 if (_is32bit) { writer.WriteUInt32((uint)ntHeader.BaseOfData); // 28 writer.WriteUInt32((uint)ntHeader.ImageBase); // 32 } else { writer.WriteUInt64(ntHeader.ImageBase); // 32 } // NT additional fields: writer.WriteUInt32((uint)ntHeader.SectionAlignment); // 36 writer.WriteUInt32((uint)ntHeader.FileAlignment); // 40 writer.WriteUInt16(ntHeader.MajorOperatingSystemVersion); // 42 writer.WriteUInt16(ntHeader.MinorOperatingSystemVersion); // 44 writer.WriteUInt16(ntHeader.MajorImageVersion); // 46 writer.WriteUInt16(ntHeader.MinorImageVersion); // 48 writer.WriteUInt16(ntHeader.MajorSubsystemVersion); // MajorSubsystemVersion 50 writer.WriteUInt16(ntHeader.MinorSubsystemVersion); // MinorSubsystemVersion 52 // Win32VersionValue (reserved, should be 0) writer.WriteUInt32(0); // 56 writer.WriteUInt32((uint)ntHeader.SizeOfImage); // 60 writer.WriteUInt32((uint)ntHeader.SizeOfHeaders); // 64 writer.WriteUInt32(ntHeader.Checksum); // 68 writer.WriteUInt16((ushort)ntHeader.Subsystem); // 70 writer.WriteUInt16((ushort)ntHeader.DllCharacteristics); if (_is32bit) { writer.WriteUInt32((uint)ntHeader.SizeOfStackReserve); // 76 writer.WriteUInt32((uint)ntHeader.SizeOfStackCommit); // 80 writer.WriteUInt32((uint)ntHeader.SizeOfHeapReserve); // 84 writer.WriteUInt32((uint)ntHeader.SizeOfHeapCommit); // 88 } else { writer.WriteUInt64(ntHeader.SizeOfStackReserve); // 80 writer.WriteUInt64(ntHeader.SizeOfStackCommit); // 88 writer.WriteUInt64(ntHeader.SizeOfHeapReserve); // 96 writer.WriteUInt64(ntHeader.SizeOfHeapCommit); // 104 } // LoaderFlags writer.WriteUInt32(0); // 92|108 // The number of data-directory entries in the remainder of the header. writer.WriteUInt32(16); // 96|112 // directory entries: writer.WriteUInt32((uint)ntHeader.ExportTable.RelativeVirtualAddress); // 100|116 writer.WriteUInt32((uint)ntHeader.ExportTable.Size); // 104|120 writer.WriteUInt32((uint)ntHeader.ImportTable.RelativeVirtualAddress); // 108|124 writer.WriteUInt32((uint)ntHeader.ImportTable.Size); // 112|128 writer.WriteUInt32((uint)ntHeader.ResourceTable.RelativeVirtualAddress); // 116|132 writer.WriteUInt32((uint)ntHeader.ResourceTable.Size); // 120|136 writer.WriteUInt32((uint)ntHeader.ExceptionTable.RelativeVirtualAddress); // 124|140 writer.WriteUInt32((uint)ntHeader.ExceptionTable.Size); // 128|144 writer.WriteUInt32((uint)ntHeader.CertificateTable.RelativeVirtualAddress); // 132|148 writer.WriteUInt32((uint)ntHeader.CertificateTable.Size); // 136|152 writer.WriteUInt32((uint)ntHeader.BaseRelocationTable.RelativeVirtualAddress); // 140|156 writer.WriteUInt32((uint)ntHeader.BaseRelocationTable.Size); // 144|160 writer.WriteUInt32((uint)ntHeader.DebugTable.RelativeVirtualAddress); // 148|164 writer.WriteUInt32((uint)ntHeader.DebugTable.Size); // 152|168 writer.WriteUInt32((uint)ntHeader.CopyrightTable.RelativeVirtualAddress); // 156|172 writer.WriteUInt32((uint)ntHeader.CopyrightTable.Size); // 160|176 writer.WriteUInt32((uint)ntHeader.GlobalPointerTable.RelativeVirtualAddress); // 164|180 writer.WriteUInt32((uint)ntHeader.GlobalPointerTable.Size); // 168|184 writer.WriteUInt32((uint)ntHeader.ThreadLocalStorageTable.RelativeVirtualAddress); // 172|188 writer.WriteUInt32((uint)ntHeader.ThreadLocalStorageTable.Size); // 176|192 writer.WriteUInt32((uint)ntHeader.LoadConfigTable.RelativeVirtualAddress); // 180|196 writer.WriteUInt32((uint)ntHeader.LoadConfigTable.Size); // 184|200 writer.WriteUInt32((uint)ntHeader.BoundImportTable.RelativeVirtualAddress); // 188|204 writer.WriteUInt32((uint)ntHeader.BoundImportTable.Size); // 192|208 writer.WriteUInt32((uint)ntHeader.ImportAddressTable.RelativeVirtualAddress); // 196|212 writer.WriteUInt32((uint)ntHeader.ImportAddressTable.Size); // 200|216 writer.WriteUInt32((uint)ntHeader.DelayImportTable.RelativeVirtualAddress); // 204|220 writer.WriteUInt32((uint)ntHeader.DelayImportTable.Size); // 208|224 writer.WriteUInt32((uint)ntHeader.CliHeaderTable.RelativeVirtualAddress); // 212|228 writer.WriteUInt32((uint)ntHeader.CliHeaderTable.Size); // 216|232 writer.WriteUInt64(0); // 224|240 // Section Headers foreach (var sectionHeader in sectionHeaders) { WriteSectionHeader(sectionHeader, writer); } writer.WriteContentTo(peStream); writer.Free(); }
private void FillInNtHeader( List<SectionHeader> sectionHeaders, int entryPointAddress, DirectoryEntry corHeader, DirectoryEntry importTable, DirectoryEntry importAddressTable, DirectoryEntry debugTable, out CoffHeader coffHeader, out NtHeader ntHeader) { short sectionCount = (short)sectionHeaders.Count; coffHeader = new CoffHeader( machine: (_properties.Machine == 0) ? Machine.I386 : _properties.Machine, numberOfSections: sectionCount, timeDateStamp: _timeStamp, pointerToSymbolTable: 0, numberOfSymbols: 0, sizeOfOptionalHeader: (short)(_is32bit ? 224 : 240), // TODO: constants characteristics: _properties.ImageCharacteristics); SectionHeader codeSection = sectionHeaders.FirstOrDefault(sh => (sh.Characteristics & SectionCharacteristics.ContainsCode) != 0); SectionHeader dataSection = sectionHeaders.FirstOrDefault(sh => (sh.Characteristics & SectionCharacteristics.ContainsInitializedData) != 0); ntHeader = new NtHeader(); ntHeader.Magic = _is32bit ? PEMagic.PE32 : PEMagic.PE32Plus; ntHeader.MajorLinkerVersion = _properties.LinkerMajorVersion; ntHeader.MinorLinkerVersion = _properties.LinkerMinorVersion; ntHeader.AddressOfEntryPoint = entryPointAddress; ntHeader.BaseOfCode = codeSection?.RelativeVirtualAddress ?? 0; ntHeader.BaseOfData = dataSection?.RelativeVirtualAddress ?? 0; ntHeader.ImageBase = _properties.BaseAddress; ntHeader.FileAlignment = _properties.FileAlignment; ntHeader.MajorSubsystemVersion = _properties.MajorSubsystemVersion; ntHeader.MinorSubsystemVersion = _properties.MinorSubsystemVersion; ntHeader.Subsystem = _properties.Subsystem; ntHeader.DllCharacteristics = _properties.DllCharacteristics; ntHeader.SizeOfStackReserve = _properties.SizeOfStackReserve; ntHeader.SizeOfStackCommit = _properties.SizeOfStackCommit; ntHeader.SizeOfHeapReserve = _properties.SizeOfHeapReserve; ntHeader.SizeOfHeapCommit = _properties.SizeOfHeapCommit; ntHeader.SizeOfCode = codeSection?.SizeOfRawData ?? 0; ntHeader.SizeOfInitializedData = sectionHeaders.Sum( sectionHeader => (sectionHeader.Characteristics & SectionCharacteristics.ContainsInitializedData) != 0 ? sectionHeader.SizeOfRawData : 0); ntHeader.SizeOfHeaders = BitArithmeticUtilities.Align(ComputeSizeOfPeHeaders(sectionCount), _properties.FileAlignment); var lastSection = sectionHeaders.Last(); ntHeader.SizeOfImage = BitArithmeticUtilities.Align(lastSection.RelativeVirtualAddress + lastSection.VirtualSize, _properties.SectionAlignment); ntHeader.SizeOfUninitializedData = 0; ntHeader.ImportAddressTable = importAddressTable; ntHeader.CliHeaderTable = corHeader; ntHeader.ImportTable = importTable; var relocSection = sectionHeaders.FirstOrDefault(sectionHeader => sectionHeader.Name == RelocationSectionName); if (relocSection != null) { ntHeader.BaseRelocationTable = new DirectoryEntry(relocSection.RelativeVirtualAddress, relocSection.VirtualSize); } ntHeader.DebugTable = debugTable; var resourceSection = sectionHeaders.FirstOrDefault(sectionHeader => sectionHeader.Name == ResourceSectionName); if (resourceSection != null) { ntHeader.ResourceTable = new DirectoryEntry(resourceSection.RelativeVirtualAddress, resourceSection.VirtualSize); } }
private void FillInNtHeader(MetadataSizes metadataSizes, int mappedFieldDataStreamRva) { // In the PE File Header this is a "Time/Date Stamp" whose description is "Time and date // the file was created in seconds since January 1st 1970 00:00:00 or 0" // However, when we want to make it deterministic we fill it in (later) with bits from the hash of the full PE file. int timeStamp = _deterministic ? 0 : (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; int textSectionRva = _textSection.RelativeVirtualAddress; _coffHeader = new CoffHeader( machine: (_properties.Machine == 0) ? Machine.I386 : _properties.Machine, numberOfSections: GetSectionCount(), timeDateStamp: timeStamp, pointerToSymbolTable: 0, numberOfSymbols: 0, sizeOfOptionalHeader: (short)(_is32bit ? 224 : 240), // TODO: constants characteristics: _properties.ImageCharacteristics); var ntHeader = _ntHeader = new NtHeader(); ntHeader.Magic = _is32bit ? PEMagic.PE32 : PEMagic.PE32Plus; ntHeader.MajorLinkerVersion = _properties.LinkerMajorVersion; ntHeader.MinorLinkerVersion = _properties.LinkerMinorVersion; ntHeader.AddressOfEntryPoint = _properties.RequiresStartupStub ? mappedFieldDataStreamRva - (_is32bit ? 6 : 10) : 0; // TODO: constants ntHeader.BaseOfCode = textSectionRva; ntHeader.BaseOfData = _rdataSection.RelativeVirtualAddress; ntHeader.ImageBase = _properties.BaseAddress; ntHeader.FileAlignment = _properties.FileAlignment; ntHeader.MajorSubsystemVersion = _properties.MajorSubsystemVersion; ntHeader.MinorSubsystemVersion = _properties.MinorSubsystemVersion; ntHeader.Subsystem = _properties.Subsystem; ntHeader.DllCharacteristics = _properties.DllCharacteristics; ntHeader.SizeOfStackReserve = _properties.SizeOfStackReserve; ntHeader.SizeOfStackCommit = _properties.SizeOfStackCommit; ntHeader.SizeOfHeapReserve = _properties.SizeOfHeapReserve; ntHeader.SizeOfHeapCommit = _properties.SizeOfHeapCommit; ntHeader.SizeOfCode = _textSection.SizeOfRawData; ntHeader.SizeOfInitializedData = _rdataSection.SizeOfRawData + _coverSection.SizeOfRawData + _sdataSection.SizeOfRawData + _tlsSection.SizeOfRawData + _resourceSection.SizeOfRawData + _relocSection.SizeOfRawData; ntHeader.SizeOfHeaders = BitArithmeticUtilities.Align(ComputeSizeOfPeHeaders(), _properties.FileAlignment); ntHeader.SizeOfImage = BitArithmeticUtilities.Align(_relocSection.RelativeVirtualAddress + _relocSection.VirtualSize, 0x2000); ntHeader.SizeOfUninitializedData = 0; ntHeader.ImportAddressTable = new DirectoryEntry( (_properties.RequiresStartupStub) ? textSectionRva : 0, _sizeOfImportAddressTable); ntHeader.CliHeaderTable = new DirectoryEntry( textSectionRva + _sizeOfImportAddressTable, size: 72); // TODO: constants if (_properties.RequiresStartupStub) { ntHeader.ImportTable = new DirectoryEntry( textSectionRva + ComputeOffsetToImportTable(metadataSizes), (_is32bit ? 66 : 70) + 13); // TODO: constants } ntHeader.BaseRelocationTable = new DirectoryEntry( (_properties.RequiresStartupStub) ? _relocSection.RelativeVirtualAddress : 0, _relocSection.VirtualSize); if (EmitPdb) { // Only the size of the fixed part of the debug table goes here. ntHeader.DebugTable = new DirectoryEntry( _textSection.RelativeVirtualAddress + ComputeOffsetToDebugTable(metadataSizes), ImageDebugDirectoryBaseSize); } if (_resourceSection.SizeOfRawData > 0) { ntHeader.ResourceTable = new DirectoryEntry( _resourceSection.RelativeVirtualAddress, _resourceSection.VirtualSize); } if (_tlsSection.SizeOfRawData > 0) { ntHeader.ThreadLocalStorageTable = new DirectoryEntry( _tlsSection.RelativeVirtualAddress, _tlsSection.SizeOfRawData); } }