/// <summary> /// Output the section with a given name. For sections existent in the source MSIL PE file /// (.text, optionally .rsrc and .reloc), we first copy the content of the input MSIL PE file /// and then call the section serialization callback to emit the extra content after the input /// section content. /// </summary> /// <param name="name">Section name</param> /// <param name="location">RVA and file location where the section will be put</param> /// <returns>Blob builder representing the section data</returns> protected override BlobBuilder SerializeSection(string name, SectionLocation location) { BlobBuilder sectionDataBuilder = null; bool haveCustomSection = _customSections.Contains(name); int sectionIndex = _peReader.PEHeaders.SectionHeaders.Count() - 1; int sectionStartRva = location.RelativeVirtualAddress; while (sectionIndex >= 0 && _peReader.PEHeaders.SectionHeaders[sectionIndex].Name != name) { sectionIndex--; } if (sectionIndex >= 0) { SectionHeader sectionHeader = _peReader.PEHeaders.SectionHeaders[sectionIndex]; int sectionOffset = (_peReader.IsLoadedImage ? sectionHeader.VirtualAddress : sectionHeader.PointerToRawData); int rvaDelta = location.RelativeVirtualAddress - sectionHeader.VirtualAddress; _sectionRvaDeltas.Add(new SectionRVADelta( startRVA: sectionHeader.VirtualAddress, endRVA: sectionHeader.VirtualAddress + Math.Max(sectionHeader.VirtualSize, sectionHeader.SizeOfRawData), deltaRVA: rvaDelta)); unsafe { int bytesToRead = Math.Min(sectionHeader.SizeOfRawData, sectionHeader.VirtualSize); BlobReader inputSectionReader = _peReader.GetEntireImage().GetReader(sectionOffset, bytesToRead); if (name == ".rsrc") { // There seems to be a bug in BlobBuilder - when we LinkSuffix to an empty blob builder, // the blob data goes out of sync and WriteContentTo outputs garbage. sectionDataBuilder = PEResourceHelper.Relocate(inputSectionReader, rvaDelta); } else { sectionDataBuilder = new BlobBuilder(); sectionDataBuilder.WriteBytes(inputSectionReader.CurrentPointer, inputSectionReader.RemainingBytes); int corHeaderRvaDelta = _peReader.PEHeaders.PEHeader.CorHeaderTableDirectory.RelativeVirtualAddress - sectionHeader.VirtualAddress; if (corHeaderRvaDelta >= 0 && corHeaderRvaDelta < bytesToRead) { // Assume COR header resides in this section, deserialize it and store its location _corHeaderFileOffset = location.PointerToRawData + corHeaderRvaDelta; inputSectionReader.Offset = corHeaderRvaDelta; _corHeaderBuilder = new CorHeaderBuilder(ref inputSectionReader); } } int alignedSize = sectionHeader.VirtualSize; // When custom section data is present, align the section size to 4K to prevent // pre-generated MSIL relocations from tampering with native relocations. if (_customSections.Contains(name)) { alignedSize = (alignedSize + 0xFFF) & ~0xFFF; } if (alignedSize > bytesToRead) { // If the number of bytes read from the source PE file is less than the virtual size, // zero pad to the end of virtual size before emitting extra section data sectionDataBuilder.WriteBytes(0, alignedSize - bytesToRead); } location = new SectionLocation( location.RelativeVirtualAddress + sectionDataBuilder.Count, location.PointerToRawData + sectionDataBuilder.Count); } } if (_sectionSerializer != null) { BlobBuilder extraData = _sectionSerializer(name, location, sectionStartRva); if (extraData != null) { if (sectionDataBuilder == null) { // See above - there's a bug due to which LinkSuffix to an empty BlobBuilder screws up the blob content. sectionDataBuilder = extraData; } else { sectionDataBuilder.LinkSuffix(extraData); } } } // Make sure the section has at least 1 byte, otherwise the PE emitter goes mad, // messes up the section map and corrups the output executable. if (sectionDataBuilder == null) { sectionDataBuilder = new BlobBuilder(); } if (sectionDataBuilder.Count == 0) { sectionDataBuilder.WriteByte(0); } return(sectionDataBuilder); }
/// <summary> /// Output the section with a given name. For sections existent in the source MSIL PE file /// (.text, optionally .rsrc and .reloc), we first copy the content of the input MSIL PE file /// and then call the section serialization callback to emit the extra content after the input /// section content. /// </summary> /// <param name="name">Section name</param> /// <param name="location">RVA and file location where the section will be put</param> /// <returns>Blob builder representing the section data</returns> protected override BlobBuilder SerializeSection(string name, SectionLocation location) { BlobBuilder sectionDataBuilder = null; int sectionStartRva = location.RelativeVirtualAddress; int outputSectionIndex = _sections.Length - 1; while (outputSectionIndex >= 0 && _sections[outputSectionIndex].Name != name) { outputSectionIndex--; } if (!_target.IsWindows) { if (outputSectionIndex > 0) { sectionStartRva = Math.Max(sectionStartRva, _sectionRVAs[outputSectionIndex - 1] + _sectionRawSizes[outputSectionIndex - 1]); } const int RVAAlign = 1 << RVABitsToMatchFilePos; sectionStartRva = AlignmentHelper.AlignUp(sectionStartRva, RVAAlign); int rvaAdjust = (location.PointerToRawData - sectionStartRva) & (RVAAlign - 1); sectionStartRva += rvaAdjust; location = new SectionLocation(sectionStartRva, location.PointerToRawData); } if (outputSectionIndex >= 0) { _sectionRVAs[outputSectionIndex] = sectionStartRva; } int inputSectionIndex = _peReader.PEHeaders.SectionHeaders.Count() - 1; while (inputSectionIndex >= 0 && _peReader.PEHeaders.SectionHeaders[inputSectionIndex].Name != name) { inputSectionIndex--; } if (inputSectionIndex >= 0) { SectionHeader sectionHeader = _peReader.PEHeaders.SectionHeaders[inputSectionIndex]; int sectionOffset = (_peReader.IsLoadedImage ? sectionHeader.VirtualAddress : sectionHeader.PointerToRawData); int rvaDelta = location.RelativeVirtualAddress - sectionHeader.VirtualAddress; _sectionRvaDeltas.Add(new SectionRVADelta( startRVA: sectionHeader.VirtualAddress, endRVA: sectionHeader.VirtualAddress + Math.Max(sectionHeader.VirtualSize, sectionHeader.SizeOfRawData), deltaRVA: rvaDelta)); int bytesToRead = Math.Min(sectionHeader.SizeOfRawData, sectionHeader.VirtualSize); BlobReader inputSectionReader = _peReader.GetEntireImage().GetReader(sectionOffset, bytesToRead); if (name == RsrcSectionName) { // There seems to be a bug in BlobBuilder - when we LinkSuffix to an empty blob builder, // the blob data goes out of sync and WriteContentTo outputs garbage. sectionDataBuilder = PEResourceHelper.Relocate(inputSectionReader, rvaDelta); } int alignedSize = sectionHeader.VirtualSize; // When custom section data is present, align the section size to 4K to prevent // pre-generated MSIL relocations from tampering with native relocations. if (_customSections.Contains(name)) { alignedSize = (alignedSize + 0xFFF) & ~0xFFF; } if (sectionDataBuilder != null) { if (alignedSize > bytesToRead) { // If the number of bytes read from the source PE file is less than the virtual size, // zero pad to the end of virtual size before emitting extra section data sectionDataBuilder.WriteBytes(0, alignedSize - bytesToRead); } location = new SectionLocation( location.RelativeVirtualAddress + sectionDataBuilder.Count, location.PointerToRawData + sectionDataBuilder.Count); } } BlobBuilder extraData = _sectionBuilder.SerializeSection(name, location); if (extraData != null) { if (sectionDataBuilder == null) { // See above - there's a bug due to which LinkSuffix to an empty BlobBuilder screws up the blob content. sectionDataBuilder = extraData; } else { sectionDataBuilder.LinkSuffix(extraData); } } // Make sure the section has at least 1 byte, otherwise the PE emitter goes mad, // messes up the section map and corrups the output executable. if (sectionDataBuilder == null) { sectionDataBuilder = new BlobBuilder(); } if (sectionDataBuilder.Count == 0) { sectionDataBuilder.WriteByte(0); } if (outputSectionIndex >= 0) { _sectionRawSizes[outputSectionIndex] = sectionDataBuilder.Count; } return(sectionDataBuilder); }