diff --git a/core/elfpatcher/include/elfpatcher/ElfPatcher.hpp b/core/elfpatcher/include/elfpatcher/ElfPatcher.hpp index 653c6f3f0..48fdbd151 100644 --- a/core/elfpatcher/include/elfpatcher/ElfPatcher.hpp +++ b/core/elfpatcher/include/elfpatcher/ElfPatcher.hpp @@ -18,6 +18,7 @@ private: static constexpr std::uint32_t PT_DYNAMIC = 2; static constexpr std::uint32_t PT_INTERP = 3; static constexpr std::uint32_t PT_NOTE = 4; + static constexpr std::uint32_t PT_PHDR = 6; static constexpr std::uint32_t PT_GNU_RELRO = 0x6474e552; static constexpr std::uint32_t PF_X = 0x1; static constexpr std::uint32_t PF_W = 0x2; @@ -66,8 +67,8 @@ private: [[nodiscard]] bool _isNullPageLoad(const Domain::ProgramHeader& ph) const; [[nodiscard]] bool _shouldSkip(const Domain::ProgramHeader& ph) const; [[nodiscard]] Domain::ProgramHeader _makeLoadHeader(std::uint64_t offset, std::uint64_t size) const; + [[nodiscard]] Domain::ProgramHeader _makePhdrHeader(std::uint64_t offset, std::uint64_t size) const; [[nodiscard]] std::vector _buildEntryStub(std::uint64_t stubVaddr, std::uint64_t realEntryVaddr) const; - void _writeInterp(std::vector& buf, std::size_t phEntOff, std::uint64_t interpOff, std::uint64_t interpSize) const; void _writeU16(std::vector& buf, std::size_t offset, std::uint16_t v) const; void _writeU32(std::vector& buf, std::size_t offset, std::uint32_t v) const; void _writeU64(std::vector& buf, std::size_t offset, std::uint64_t v) const; diff --git a/core/elfpatcher/src/ElfPatcher.cpp b/core/elfpatcher/src/ElfPatcher.cpp index 059d52d36..fed9e04fd 100644 --- a/core/elfpatcher/src/ElfPatcher.cpp +++ b/core/elfpatcher/src/ElfPatcher.cpp @@ -55,7 +55,7 @@ void ElfPatcher::_writeProgramHeader(std::vector& buf, std::size_t Domain::ProgramHeader ElfPatcher::_makeLoadHeader(std::uint64_t offset, std::uint64_t size) const { Domain::ProgramHeader ph{}; ph.Type = PT_LOAD; - ph.Flags = PF_R; + ph.Flags = PF_R | PF_W; ph.Offset = offset; ph.MappedAddress = offset; ph.PhysicalAddress = offset; @@ -65,17 +65,17 @@ Domain::ProgramHeader ElfPatcher::_makeLoadHeader(std::uint64_t offset, std::uin return ph; } -void ElfPatcher::_writeInterp(std::vector& buf, std::size_t phEntOff, std::uint64_t interpOff, std::uint64_t interpSize) const { +Domain::ProgramHeader ElfPatcher::_makePhdrHeader(std::uint64_t offset, std::uint64_t size) const { Domain::ProgramHeader ph{}; - ph.Type = PT_INTERP; + ph.Type = PT_PHDR; ph.Flags = PF_R; - ph.Offset = interpOff; - ph.MappedAddress = interpOff; - ph.PhysicalAddress = interpOff; - ph.FileSize = interpSize; - ph.MemorySize = interpSize; - ph.Alignment = 1; - _writeProgramHeader(buf, phEntOff, ph); + ph.Offset = offset; + ph.MappedAddress = offset; + ph.PhysicalAddress = offset; + ph.FileSize = size; + ph.MemorySize = size; + ph.Alignment = 8; + return ph; } std::vector ElfPatcher::_buildEntryStub(const std::uint64_t stubVaddr, const std::uint64_t realEntryVaddr) const { @@ -217,44 +217,55 @@ std::vector ElfPatcher::Patch( for (std::size_t i = 0; i < interpSize; i++) buf.push_back(static_cast(kInterp[i])); - const std::uint64_t extraBlockOff = dynStrOff; - const std::uint64_t extraBlockSize = static_cast(buf.size()) - extraBlockOff; - std::uint16_t keptCount = 0; for (const auto& ph : originalHeaders) { if (_shouldSkip(ph)) continue; keptCount++; } - const std::uint16_t neededPh = keptCount + 3; + const std::uint16_t neededPh = keptCount + 4; if (neededPh > phNum) throw Domain::RelinkerException( "Not enough program header slots: need " + std::to_string(neededPh) + ", available " + std::to_string(phNum)); + alignBuf(buf, 8); + const std::uint64_t phCopyOff = static_cast(buf.size()); + const std::uint64_t phCopySize = static_cast(neededPh) * phEntSize; + buf.resize(buf.size() + phCopySize, 0); + + const std::uint64_t extraBlockOff = dynStrOff; + const std::uint64_t extraBlockSize = static_cast(buf.size()) - extraBlockOff; + + const auto writePhBoth = [&](std::uint16_t index, const Domain::ProgramHeader& ph) { + const std::size_t mainOff = static_cast(phOff) + index * phEntSize; + const std::size_t copyOff = static_cast(phCopyOff) + index * phEntSize; + _writeProgramHeader(buf, mainOff, ph); + _writeProgramHeader(buf, copyOff, ph); + }; + std::uint16_t writtenPh = 0; + + writePhBoth(writtenPh, _makePhdrHeader(phCopyOff, phCopySize)); + writtenPh++; + for (const auto& ph : originalHeaders) { if (_shouldSkip(ph)) continue; - const std::size_t phEntOff = static_cast(phOff) + writtenPh * phEntSize; if (ph.Type == PT_LOAD) { Domain::ProgramHeader fixed = ph; fixed.Flags = _fixLoadFlags(ph.Flags); - _writeProgramHeader(buf, phEntOff, fixed); + writePhBoth(writtenPh, fixed); } else { - _writeProgramHeader(buf, phEntOff, ph); + writePhBoth(writtenPh, ph); } writtenPh++; } - { - const std::size_t phEntOff = static_cast(phOff) + writtenPh * phEntSize; - _writeProgramHeader(buf, phEntOff, _makeLoadHeader(extraBlockOff, extraBlockSize)); - writtenPh++; - } + writePhBoth(writtenPh, _makeLoadHeader(extraBlockOff, extraBlockSize)); + writtenPh++; { - const std::size_t phEntOff = static_cast(phOff) + writtenPh * phEntSize; Domain::ProgramHeader dynPh{}; dynPh.Type = PT_DYNAMIC; dynPh.Flags = PF_R | PF_W; @@ -264,17 +275,26 @@ std::vector ElfPatcher::Patch( dynPh.FileSize = dynSegBuf.size(); dynPh.MemorySize = dynSegBuf.size(); dynPh.Alignment = 8; - _writeProgramHeader(buf, phEntOff, dynPh); + writePhBoth(writtenPh, dynPh); writtenPh++; } { - const std::size_t phEntOff = static_cast(phOff) + writtenPh * phEntSize; - _writeInterp(buf, phEntOff, interpOff, interpSize); + Domain::ProgramHeader interpPh{}; + interpPh.Type = PT_INTERP; + interpPh.Flags = PF_R; + interpPh.Offset = interpOff; + interpPh.MappedAddress = interpOff; + interpPh.PhysicalAddress = interpOff; + interpPh.FileSize = interpSize; + interpPh.MemorySize = interpSize; + interpPh.Alignment = 1; + writePhBoth(writtenPh, interpPh); writtenPh++; } _writeU16(buf, 56, writtenPh); + _writeU64(buf, 32, phCopyOff); static constexpr char kShStrTab[] = "\0.shstrtab\0.dynstr\0.dynsym\0.dynamic\0.text"; constexpr std::uint32_t nameShStrTab = 1;