From 0b1fe04878e55500fdeeb0d66de2eaf30a0b1ddf Mon Sep 17 00:00:00 2001 From: SpecterDev Date: Sun, 19 Dec 2021 23:39:53 -0500 Subject: [PATCH] Fix-up .dynamic section --- cmd/create-fself/main.go | 3 ++ pkg/oelf/OELFGenProgramHeaders.go | 13 ++++++- pkg/oelf/OELFRewriteData.go | 62 +++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/cmd/create-fself/main.go b/cmd/create-fself/main.go index c823b00..b964e2a 100644 --- a/cmd/create-fself/main.go +++ b/cmd/create-fself/main.go @@ -105,6 +105,9 @@ func main() { err = orbisElf.RewriteProgramHeaders() check(err) + // Overwrite .dynamic section header to point to the new dynamic table + err = orbisElf.RewriteDynamicSectionHeader() + // Commit err = orbisElf.FinalFile.Close() check(err) diff --git a/pkg/oelf/OELFGenProgramHeaders.go b/pkg/oelf/OELFGenProgramHeaders.go index 7da92e9..0e55010 100644 --- a/pkg/oelf/OELFGenProgramHeaders.go +++ b/pkg/oelf/OELFGenProgramHeaders.go @@ -25,6 +25,9 @@ func (orbisElf *OrbisElf) GenerateProgramHeaders() error { procParamSection = orbisElf.ElfToConvert.Section(".data.sce_module_param") } + // Get GNU_RELRO header pre-emptively (we'll need to check it to eliminate duplicate PT_LOAD headers) + gnuRelroSegment := orbisElf.getProgramHeader(elf.PT_GNU_RELRO, elf.PF_R) + // First pass: drop program headers that we don't need and copy all others for _, progHeader := range orbisElf.ElfToConvert.Progs { // PT_LOAD read-only should be consolidated into PT_LOAD for .text @@ -33,12 +36,18 @@ func (orbisElf *OrbisElf) GenerateProgramHeaders() error { } // PT_LOAD for relro will be handled by SCE_RELRO, we can get rid of it - if relroSection != nil { - if progHeader.Type == elf.PT_LOAD && progHeader.Off == relroSection.Offset { + if gnuRelroSegment != nil { + if progHeader.Type == elf.PT_LOAD && progHeader.Off == gnuRelroSegment.Off { continue } } + // GNU_RELRO will sometimes get generated even if no .data.rel.ro is present. This is bad for PS4 because the + // header will be unaligned and it's not necessary. Get rid of it if there's no relro section. + if progHeader.Type == elf.PT_GNU_RELRO && relroSection == nil { + continue + } + // GNU_STACK can be dropped, PS4 doesn't need it if progHeader.Type == elf.PT_GNU_STACK { continue diff --git a/pkg/oelf/OELFRewriteData.go b/pkg/oelf/OELFRewriteData.go index ab9f758..b8820d7 100644 --- a/pkg/oelf/OELFRewriteData.go +++ b/pkg/oelf/OELFRewriteData.go @@ -122,3 +122,65 @@ func (orbisElf *OrbisElf) RewriteInterpreter(interpreter string) error { _, err = orbisElf.FinalFile.WriteAt(interpreterBuff, rewriteOffset) return err } + +// RewriteDynamicSectionHeader will overwrite the address of the .dynamic section with the given address. Returns +// an error if the write failed, nil otherwise. +func (orbisElf *OrbisElf) RewriteDynamicSectionHeader() error { + var ( + inputFile *os.File + err error + ) + + // Get the section header offset info from the original file + inputHdr := new(elf.Header64) + + if inputFile, err = os.Open(orbisElf.ElfToConvertName); err != nil { + return err + } + + if _, err = inputFile.Seek(0, io.SeekStart); err != nil { + return err + } + + if err = binary.Read(inputFile, orbisElf.ElfToConvert.ByteOrder, inputHdr); err != nil { + return err + } + + sectionHeadersOffset := inputHdr.Shoff + + // Find the dynamic header + for i := uint16(0); i < inputHdr.Shnum; i++ { + sectionHdr := new(elf.Section64) + sectionHeaderOffset := int64(sectionHeadersOffset + uint64(i*inputHdr.Shentsize)) + + if _, err = inputFile.Seek(sectionHeaderOffset, io.SeekStart); err != nil { + return err + } + + if err = binary.Read(inputFile, orbisElf.ElfToConvert.ByteOrder, sectionHdr); err != nil { + return err + } + + if sectionHdr.Type == uint32(elf.SHT_DYNAMIC) { + sectionHeaderBuff := new(bytes.Buffer) + + // Rewrite the address + sectionHdr.Off = _offsetOfDynamic + sectionHdr.Addr = _offsetOfDynamic + sectionHdr.Size = _sizeOfDynamic + + // Commit the write + if err := binary.Write(sectionHeaderBuff, binary.LittleEndian, sectionHdr); err != nil { + return err + } + + if _, err := orbisElf.FinalFile.WriteAt(sectionHeaderBuff.Bytes(), sectionHeaderOffset); err != nil { + return err + } + + break + } + } + + return nil +}