rum-goggles/vendor/github.com/jchv/go-winloader/internal/pe/reloc.go

178 lines
5.1 KiB
Go
Raw Normal View History

2024-02-23 16:39:16 +00:00
package pe
import (
"encoding/binary"
"errors"
"fmt"
"io"
)
// BaseRelocation is a parsed PE base relocation.
type BaseRelocation struct {
// Relative virtual address of offset (that is, 0 == first byte of PE.)
Offset uint64
// Type of base relocation using the ImageRelBased* constants.
Type int
}
// LoadBaseRelocs loads relocations from memory.
func LoadBaseRelocs(m *Module, mem io.ReadSeeker) []BaseRelocation {
relocs := []BaseRelocation{}
dir := m.Header.OptionalHeader.DataDirectory[ImageDirectoryEntryBaseReloc]
if dir.Size == 0 {
return relocs
}
n := uint32(0)
mem.Seek(int64(dir.VirtualAddress), io.SeekStart)
for n < dir.Size {
hdr := ImageBaseRelocation{}
binary.Read(mem, binary.LittleEndian, &hdr)
data := make([]uint16, hdr.SizeOfBlock/2-4)
binary.Read(mem, binary.LittleEndian, &data)
for _, i := range data {
relocs = append(relocs, BaseRelocation{
Offset: uint64(hdr.VirtualAddress) + uint64(i&0xFFF),
Type: int(i >> 12),
})
}
n += hdr.SizeOfBlock
}
return relocs
}
// Relocate performs a series of relocations on m, where address is the load
// address and original is the original address. The ReadWriteSeeker is
// assumed to have the PE image at offset 0.
func Relocate(machine int, rels []BaseRelocation, address uint64, original uint64, m io.ReadWriteSeeker, o binary.ByteOrder) error {
b := [8]byte{}
delta := address - original
if delta == 0 {
return nil
}
read := func(off uint64, cb int) error {
m.Seek(int64(off), io.SeekStart)
err := readfully(m, b[0:cb])
if err != nil {
return err
}
m.Seek(int64(-cb), io.SeekCurrent)
return nil
}
for _, rel := range rels {
switch rel.Type {
case ImageRelBasedAbsolute:
break
case ImageRelBasedHigh:
if err := read(rel.Offset, 2); err != nil {
return err
}
o.PutUint16(b[0:2], uint16(uint64(o.Uint16(b[:2]))+(delta>>16)))
if _, err := m.Write(b[0:2]); err != nil {
return err
}
break
case ImageRelBasedLow:
if err := read(rel.Offset, 2); err != nil {
return err
}
o.PutUint16(b[0:2], uint16(uint64(o.Uint16(b[:2]))+(delta>>0)))
if _, err := m.Write(b[0:2]); err != nil {
return err
}
break
case ImageRelBasedHighLow:
if err := read(rel.Offset, 4); err != nil {
return err
}
o.PutUint32(b[0:4], uint32(uint64(o.Uint32(b[:4]))+delta))
if _, err := m.Write(b[0:4]); err != nil {
return err
}
break
case ImageRelBasedDir64:
if err := read(rel.Offset, 8); err != nil {
return err
}
o.PutUint64(b[0:8], uint64(o.Uint64(b[:8]))+delta)
if _, err := m.Write(b[0:8]); err != nil {
return err
}
break
// Could use some help for ensuring we have proper support for
// machine-specific relocations. If you are interested in this
// use case for some reason, feel free to send PRs. -- john
case ImageRelBasedMachineSpecific5:
switch machine {
// MIPS: JMP reloc
case ImageFileMachineR3000, ImageFileMachineR3000BE,
ImageFileMachineR4000, ImageFileMachineR10000,
ImageFileMachineWCEMIPSv2, ImageFileMachineMIPS16,
ImageFileMachineMIPSFPU, ImageFileMachineMIPSFPU16:
return errors.New("MIPS JMP reloc not implemented")
// ARM: MOV32 reloc
case ImageFileMachineARM, ImageFileMachineTHUMB,
ImageFileMachineARMNT:
return errors.New("ARM MOV32 reloc not implemented")
// RISC-V: HI20 reloc
case ImageFileMachineRISCV32, ImageFileMachineRISCV64,
ImageFileMachineRISCV128:
return errors.New("RISC-V HI20 reloc not implemented")
default:
return fmt.Errorf("unknown machine-specific relocation type %d on machine type %04x", rel.Type, machine)
}
case ImageRelBasedMachineSpecific7:
switch machine {
// THUMB: MOV32 reloc
case ImageFileMachineARM, ImageFileMachineTHUMB,
ImageFileMachineARMNT:
return errors.New("THUMB MOV32 reloc not implemented")
// RISC-V: LOW12I reloc
case ImageFileMachineRISCV32, ImageFileMachineRISCV64,
ImageFileMachineRISCV128:
return errors.New("RISC-V LOW12I reloc not implemented")
default:
return fmt.Errorf("unknown machine-specific relocation type %d on machine type %04x", rel.Type, machine)
}
case ImageRelBasedMachineSpecific8:
switch machine {
// RISC-V: LOW12S reloc
case ImageFileMachineRISCV32, ImageFileMachineRISCV64,
ImageFileMachineRISCV128:
return errors.New("RISC-V LOW12S reloc not implemented")
default:
return fmt.Errorf("unknown machine-specific relocation type %d on machine type %04x", rel.Type, machine)
}
case ImageRelBasedMachineSpecific9:
switch machine {
// MIPS: JMP16 reloc
case ImageFileMachineR3000, ImageFileMachineR3000BE,
ImageFileMachineR4000, ImageFileMachineR10000,
ImageFileMachineWCEMIPSv2, ImageFileMachineMIPS16,
ImageFileMachineMIPSFPU, ImageFileMachineMIPSFPU16:
return errors.New("MIPS JMP16 reloc not implemented")
// Itanium: Imm64 reloc
case ImageFileMachineIA64:
return errors.New("Itanium Imm64 reloc not implemented")
default:
return fmt.Errorf("unknown machine-specific relocation type %d on machine type %04x", rel.Type, machine)
}
default:
return fmt.Errorf("unknown relocation type %d", rel.Type)
}
}
return nil
}