elfpatch.go raw

   1  package builder
   2  
   3  import (
   4  	"debug/elf"
   5  	"fmt"
   6  	"os"
   7  )
   8  
   9  func getElfSectionData(executable string, sectionName string) ([]byte, elf.FileHeader, error) {
  10  	elfFile, err := elf.Open(executable)
  11  	if err != nil {
  12  		return nil, elf.FileHeader{}, err
  13  	}
  14  	defer elfFile.Close()
  15  
  16  	section := elfFile.Section(sectionName)
  17  	if section == nil {
  18  		return nil, elf.FileHeader{}, fmt.Errorf("could not find %s section", sectionName)
  19  	}
  20  
  21  	data, err := section.Data()
  22  
  23  	return data, elfFile.FileHeader, err
  24  }
  25  
  26  func replaceElfSection(executable string, sectionName string, data []byte) error {
  27  	fp, err := os.OpenFile(executable, os.O_RDWR, 0)
  28  	if err != nil {
  29  		return err
  30  	}
  31  	defer fp.Close()
  32  
  33  	elfFile, err := elf.Open(executable)
  34  	if err != nil {
  35  		return err
  36  	}
  37  	defer elfFile.Close()
  38  
  39  	section := elfFile.Section(sectionName)
  40  	if section == nil {
  41  		return fmt.Errorf("could not find %s section", sectionName)
  42  	}
  43  
  44  	// Implicitly check for compressed sections
  45  	if section.Size != section.FileSize {
  46  		return fmt.Errorf("expected section %s to have identical size and file size, got %d and %d", sectionName, section.Size, section.FileSize)
  47  	}
  48  
  49  	// Only permit complete replacement of section
  50  	if section.Size != uint64(len(data)) {
  51  		return fmt.Errorf("expected section %s to have size %d, was actually %d", sectionName, len(data), section.Size)
  52  	}
  53  
  54  	// Write the replacement section data
  55  	_, err = fp.WriteAt(data, int64(section.Offset))
  56  	return err
  57  }
  58