178 lines
5.1 KiB
Go
178 lines
5.1 KiB
Go
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
|
|
}
|