github.com/notti/go-dynamic@v0.0.0-20190619201224-fc443047424c/steps/1_dynamic/rewrite.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"debug/elf"
     6  	"encoding/binary"
     7  	"errors"
     8  	"io"
     9  	"log"
    10  	"os"
    11  	"sort"
    12  )
    13  
    14  const (
    15  	in     = "a.out"
    16  	out    = "dyn"
    17  	interp = "/lib64/ld-linux-x86-64.so.2"
    18  )
    19  
    20  var libs = []string{"libc.so.6"}
    21  var relocations = map[string]string{
    22  	"__printf": "puts",
    23  }
    24  
    25  func doCopy() {
    26  	src, err := os.Open(in)
    27  	if err != nil {
    28  		log.Fatal("couldn't open", in, ":", err)
    29  	}
    30  	defer src.Close()
    31  	dst, err := os.OpenFile(out, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0777)
    32  	if err != nil {
    33  		log.Fatal("couldn't create", out, ":", err)
    34  	}
    35  	defer dst.Close()
    36  	_, err = io.Copy(dst, src)
    37  	if err != nil {
    38  		log.Fatal("couldn't copy:", err)
    39  	}
    40  }
    41  
    42  type elfFile struct {
    43  	f         *os.File
    44  	e         *elf.File
    45  	phoff     uint64
    46  	phentsize uint64
    47  	shoff     uint64
    48  	shentsize uint64
    49  	shstrndx  uint64
    50  	buffer    [1024]byte
    51  }
    52  
    53  func openElfFile(name string) (*elfFile, error) {
    54  	ret := &elfFile{}
    55  	var err error
    56  	ret.f, err = os.OpenFile(name, os.O_RDWR, 0777)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	ret.e, err = elf.NewFile(ret.f)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	_, err = ret.Seek(0, io.SeekCurrent)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	switch ret.e.Class {
    71  	case elf.ELFCLASS32:
    72  		var hdr elf.Header32
    73  		err = ret.ReadData(&hdr)
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  		ret.phoff = uint64(hdr.Phoff)
    78  		ret.phentsize = uint64(hdr.Phentsize)
    79  		ret.shoff = uint64(hdr.Shoff)
    80  		ret.shentsize = uint64(hdr.Shentsize)
    81  		ret.shstrndx = uint64(hdr.Shstrndx)
    82  	case elf.ELFCLASS64:
    83  		var hdr elf.Header64
    84  		err = ret.ReadData(&hdr)
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  		ret.phoff = hdr.Phoff
    89  		ret.phentsize = uint64(hdr.Phentsize)
    90  		ret.shoff = hdr.Shoff
    91  		ret.shentsize = uint64(hdr.Shentsize)
    92  		ret.shstrndx = uint64(hdr.Shstrndx)
    93  	}
    94  
    95  	return ret, nil
    96  }
    97  
    98  func (e *elfFile) Seek(where int64, whence int) (int64, error) {
    99  	return e.f.Seek(where, whence)
   100  }
   101  
   102  func (e *elfFile) ReadData(data interface{}) error {
   103  	return binary.Read(e.f, e.e.ByteOrder, data)
   104  }
   105  
   106  func (e *elfFile) WriteData(data interface{}) error {
   107  	return binary.Write(e.f, e.e.ByteOrder, data)
   108  }
   109  
   110  func (e *elfFile) Write(b []byte) error {
   111  	_, err := e.f.Write(b)
   112  	return err
   113  }
   114  
   115  func (e *elfFile) WriteAt(b []byte, off uint64) error {
   116  	_, err := e.f.WriteAt(b, int64(off))
   117  	return err
   118  }
   119  
   120  func (e *elfFile) Read8() (uint8, error) {
   121  	_, err := e.f.Read(e.buffer[:1])
   122  	return e.buffer[0], err
   123  }
   124  
   125  func (e *elfFile) Read16() (uint16, error) {
   126  	_, err := e.f.Read(e.buffer[:2])
   127  	return e.e.ByteOrder.Uint16(e.buffer[:]), err
   128  }
   129  
   130  func (e *elfFile) Read32() (uint32, error) {
   131  	_, err := e.f.Read(e.buffer[:4])
   132  	return e.e.ByteOrder.Uint32(e.buffer[:]), err
   133  }
   134  
   135  func (e *elfFile) Read64() (uint64, error) {
   136  	_, err := e.f.Read(e.buffer[:8])
   137  	return e.e.ByteOrder.Uint64(e.buffer[:]), err
   138  }
   139  
   140  func (e *elfFile) Read8At(where int64) (uint8, error) {
   141  	_, err := e.f.ReadAt(e.buffer[:1], where)
   142  	return e.buffer[0], err
   143  }
   144  
   145  func (e *elfFile) Read16At(where int64) (uint16, error) {
   146  	_, err := e.f.ReadAt(e.buffer[:2], where)
   147  	return e.e.ByteOrder.Uint16(e.buffer[:]), err
   148  }
   149  
   150  func (e *elfFile) Read32At(where int64) (uint32, error) {
   151  	_, err := e.f.ReadAt(e.buffer[:4], where)
   152  	return e.e.ByteOrder.Uint32(e.buffer[:]), err
   153  }
   154  
   155  func (e *elfFile) Read64At(where int64) (uint64, error) {
   156  	_, err := e.f.ReadAt(e.buffer[:8], where)
   157  	return e.e.ByteOrder.Uint64(e.buffer[:]), err
   158  }
   159  
   160  func (e *elfFile) Write8(data uint8) error {
   161  	_, err := e.f.Write([]byte{data})
   162  	return err
   163  }
   164  
   165  func (e *elfFile) Write16(data uint16) error {
   166  	e.e.ByteOrder.PutUint16(e.buffer[:], data)
   167  	_, err := e.f.Write(e.buffer[:2])
   168  	return err
   169  }
   170  
   171  func (e *elfFile) Write32(data uint32) error {
   172  	e.e.ByteOrder.PutUint32(e.buffer[:], data)
   173  	_, err := e.f.Write(e.buffer[:4])
   174  	return err
   175  }
   176  
   177  func (e *elfFile) Write64(data uint64) error {
   178  	e.e.ByteOrder.PutUint64(e.buffer[:], data)
   179  	_, err := e.f.Write(e.buffer[:8])
   180  	return err
   181  }
   182  
   183  func (e *elfFile) Write8At(data uint8, where uint64) error {
   184  	return e.WriteAt([]byte{data}, where)
   185  }
   186  
   187  func (e *elfFile) Write16At(data uint16, where uint64) error {
   188  	e.e.ByteOrder.PutUint16(e.buffer[:], data)
   189  	return e.WriteAt(e.buffer[:2], where)
   190  }
   191  
   192  func (e *elfFile) Write32At(data uint32, where uint64) error {
   193  	e.e.ByteOrder.PutUint32(e.buffer[:], data)
   194  	return e.WriteAt(e.buffer[:4], where)
   195  }
   196  
   197  func (e *elfFile) Write64At(data uint64, where uint64) error {
   198  	e.e.ByteOrder.PutUint64(e.buffer[:], data)
   199  	return e.WriteAt(e.buffer[:8], where)
   200  }
   201  
   202  func (e *elfFile) WriteSections() error {
   203  	if _, err := e.f.Seek(int64(e.shoff), io.SeekStart); err != nil {
   204  		return err
   205  	}
   206  	shstrtab := 0
   207  	shstrtabpos := e.shoff
   208  	names := make([]uint64, len(e.e.Sections))
   209  	for i, sec := range e.e.Sections {
   210  		names[i] = e.shoff - shstrtabpos
   211  		if err := e.Write(append([]byte(sec.Name), 0)); err != nil {
   212  			return err
   213  		}
   214  		e.shoff += uint64(len(sec.Name)) + 1
   215  		if sec.Name == ".shstrtab" {
   216  			shstrtab = i
   217  		}
   218  	}
   219  	e.e.Sections[shstrtab].Offset = shstrtabpos
   220  	e.e.Sections[shstrtab].FileSize = e.shoff - shstrtabpos
   221  
   222  	for i, sec := range e.e.Sections {
   223  		if err := e.WriteSection(sec.SectionHeader, names[i]); err != nil {
   224  			return err
   225  		}
   226  	}
   227  	switch e.e.Class {
   228  	case elf.ELFCLASS32:
   229  		if err := e.Write32At(uint32(e.shoff), 0x20); err != nil {
   230  			return err
   231  		}
   232  		if err := e.Write16At(uint16(len(e.e.Sections)), 0x30); err != nil {
   233  			return err
   234  		}
   235  	case elf.ELFCLASS64:
   236  		if err := e.Write64At(e.shoff, 0x28); err != nil {
   237  			return err
   238  		}
   239  		if err := e.Write16At(uint16(len(e.e.Sections)), 0x3C); err != nil {
   240  			return err
   241  		}
   242  	}
   243  	return nil
   244  }
   245  
   246  func (e *elfFile) WriteSection(sh elf.SectionHeader, name uint64) error {
   247  	switch e.e.Class {
   248  	case elf.ELFCLASS32:
   249  		hdr := elf.Section32{
   250  			Name:      uint32(name),
   251  			Type:      uint32(sh.Type),
   252  			Flags:     uint32(sh.Flags),
   253  			Addr:      uint32(sh.Addr),
   254  			Off:       uint32(sh.Offset),
   255  			Size:      uint32(sh.FileSize),
   256  			Link:      sh.Link,
   257  			Info:      sh.Info,
   258  			Addralign: uint32(sh.Addralign),
   259  			Entsize:   uint32(sh.Entsize),
   260  		}
   261  		return e.WriteData(hdr)
   262  	case elf.ELFCLASS64:
   263  		hdr := elf.Section64{
   264  			Name:      uint32(name),
   265  			Type:      uint32(sh.Type),
   266  			Flags:     uint64(sh.Flags),
   267  			Addr:      sh.Addr,
   268  			Off:       sh.Offset,
   269  			Size:      sh.FileSize,
   270  			Link:      sh.Link,
   271  			Info:      sh.Info,
   272  			Addralign: sh.Addralign,
   273  			Entsize:   sh.Entsize,
   274  		}
   275  		return e.WriteData(hdr)
   276  	}
   277  	// compression header not handeled
   278  	return errors.New("Unknown elf bit size")
   279  }
   280  
   281  func (e *elfFile) WritePrograms() error {
   282  	if _, err := e.Seek(int64(e.phoff), io.SeekStart); err != nil {
   283  		return err
   284  	}
   285  	for _, prog := range e.e.Progs {
   286  		if err := e.WriteProgram(prog.ProgHeader); err != nil {
   287  			return err
   288  		}
   289  	}
   290  	switch e.e.Class {
   291  	case elf.ELFCLASS32:
   292  		if err := e.Write32At(uint32(e.phoff), 0x1C); err != nil {
   293  			return err
   294  		}
   295  		if err := e.Write16At(uint16(len(e.e.Progs)), 0x2C); err != nil {
   296  			return err
   297  		}
   298  	case elf.ELFCLASS64:
   299  		if err := e.Write64At(e.phoff, 0x20); err != nil {
   300  			return err
   301  		}
   302  		if err := e.Write16At(uint16(len(e.e.Progs)), 0x38); err != nil {
   303  			return err
   304  		}
   305  	}
   306  	return nil
   307  }
   308  
   309  func (e *elfFile) WriteProgram(ph elf.ProgHeader) error {
   310  	switch e.e.Class {
   311  	case elf.ELFCLASS32:
   312  		hdr := elf.Prog32{
   313  			Type:   uint32(ph.Type),
   314  			Flags:  uint32(ph.Flags),
   315  			Off:    uint32(ph.Off),
   316  			Vaddr:  uint32(ph.Vaddr),
   317  			Paddr:  uint32(ph.Paddr),
   318  			Filesz: uint32(ph.Filesz),
   319  			Memsz:  uint32(ph.Memsz),
   320  			Align:  uint32(ph.Align),
   321  		}
   322  		return e.WriteData(hdr)
   323  	case elf.ELFCLASS64:
   324  		hdr := elf.Prog64{
   325  			Type:   uint32(ph.Type),
   326  			Flags:  uint32(ph.Flags),
   327  			Off:    ph.Off,
   328  			Vaddr:  ph.Vaddr,
   329  			Paddr:  ph.Paddr,
   330  			Filesz: ph.Filesz,
   331  			Memsz:  ph.Memsz,
   332  			Align:  ph.Align,
   333  		}
   334  		return e.WriteData(hdr)
   335  	}
   336  	return errors.New("Unknown elf bit size")
   337  }
   338  
   339  func (e *elfFile) Read(b []byte) error {
   340  	_, err := e.f.Read(b)
   341  	return err
   342  }
   343  
   344  func (e *elfFile) Copy(src, dst int64, length int) error {
   345  	buffer := make([]byte, length)
   346  	_, err := e.Seek(src, io.SeekStart)
   347  	if err != nil {
   348  		return err
   349  	}
   350  	err = e.Read(buffer)
   351  	if err != nil {
   352  		return err
   353  	}
   354  	_, err = e.Seek(dst, io.SeekStart)
   355  	if err != nil {
   356  		return err
   357  	}
   358  	err = e.Write(buffer)
   359  	if err != nil {
   360  		return err
   361  	}
   362  	return nil
   363  }
   364  
   365  func (e *elfFile) Close() error {
   366  	return e.f.Close()
   367  }
   368  
   369  // Dyn contains a single entry of the dynamic table
   370  type Dyn struct {
   371  	Tag elf.DynTag
   372  	Val uint64
   373  }
   374  
   375  func padding(addr, align uint64) uint64 {
   376  	align1 := align - 1
   377  	return (align - (addr & align1)) & align1
   378  }
   379  
   380  // DynSymbol represents a dynamic symbol
   381  type DynSymbol struct {
   382  	Name    string
   383  	Value   uint64
   384  	Size    uint64
   385  	Bind    elf.SymBind
   386  	Type    elf.SymType
   387  	Vis     elf.SymVis
   388  	Section int
   389  }
   390  
   391  func (e *elfFile) makeDynsym(elements []DynSymbol) (dynsym, dynstr []byte) {
   392  	sym := &bytes.Buffer{}
   393  	str := &bytes.Buffer{}
   394  	for _, elem := range elements {
   395  		namei := str.Len()
   396  		str.Write(append([]byte(elem.Name), 0))
   397  		switch e.e.Class {
   398  		case elf.ELFCLASS32:
   399  			binary.Write(sym, e.e.ByteOrder, elf.Sym32{
   400  				Name:  uint32(namei),
   401  				Value: uint32(elem.Value),
   402  				Size:  uint32(elem.Size),
   403  				Info:  byte(elem.Bind)<<4 | byte(elem.Type)&0x0f,
   404  				Other: byte(elem.Vis) & 0x03,
   405  				Shndx: uint16(elem.Section),
   406  			})
   407  		case elf.ELFCLASS64:
   408  			binary.Write(sym, e.e.ByteOrder, elf.Sym64{
   409  				Name:  uint32(namei),
   410  				Value: uint64(elem.Value),
   411  				Size:  uint64(elem.Size),
   412  				Info:  byte(elem.Bind)<<4 | byte(elem.Type)&0x0f,
   413  				Other: byte(elem.Vis) & 0x03,
   414  				Shndx: uint16(elem.Section),
   415  			})
   416  		}
   417  	}
   418  	if str.Len() == 0 {
   419  		str.WriteByte(0)
   420  	}
   421  	return sym.Bytes(), str.Bytes()
   422  }
   423  
   424  func (e *elfFile) makeDynsec(elements []Dyn) []byte {
   425  	ret := &bytes.Buffer{}
   426  	switch e.e.Class {
   427  	case elf.ELFCLASS32:
   428  		var secs []elf.Dyn32
   429  		for _, sec := range elements {
   430  			secs = append(secs, elf.Dyn32{
   431  				Tag: int32(sec.Tag),
   432  				Val: uint32(sec.Val),
   433  			})
   434  		}
   435  		binary.Write(ret, e.e.ByteOrder, secs)
   436  	case elf.ELFCLASS64:
   437  		var secs []elf.Dyn64
   438  		for _, sec := range elements {
   439  			secs = append(secs, elf.Dyn64{
   440  				Tag: int64(sec.Tag),
   441  				Val: uint64(sec.Val),
   442  			})
   443  		}
   444  		binary.Write(ret, e.e.ByteOrder, secs)
   445  	}
   446  	return ret.Bytes()
   447  }
   448  
   449  // RelSymbol represents a symbol in need of relocation
   450  type RelSymbol struct {
   451  	Off   uint64
   452  	SymNo uint64
   453  }
   454  
   455  func (e *elfFile) makeDynRel(symbols []RelSymbol) ([]byte, bool, uint64) {
   456  	ret := &bytes.Buffer{}
   457  	var rela bool
   458  	var relt uint64
   459  	switch e.e.Machine {
   460  	case elf.EM_386:
   461  		rela = false
   462  		relt = uint64(elf.R_386_JMP_SLOT)
   463  	case elf.EM_X86_64:
   464  		rela = true
   465  		relt = uint64(elf.R_X86_64_JMP_SLOT)
   466  	default:
   467  		log.Panic("Unknown machine type ", e.e.Machine)
   468  	}
   469  
   470  	var relsz uint64
   471  
   472  	switch e.e.Class {
   473  	case elf.ELFCLASS32:
   474  		if rela {
   475  			for _, symbol := range symbols {
   476  				binary.Write(ret, e.e.ByteOrder, elf.Rela32{
   477  					Off:  uint32(symbol.Off),
   478  					Info: uint32(symbol.SymNo<<8 | relt),
   479  				})
   480  			}
   481  			relsz = 12
   482  		} else {
   483  			for _, symbol := range symbols {
   484  
   485  				binary.Write(ret, e.e.ByteOrder, elf.Rel32{
   486  					Off:  uint32(symbol.Off),
   487  					Info: uint32(symbol.SymNo<<8 | relt),
   488  				})
   489  			}
   490  			relsz = 8
   491  		}
   492  	case elf.ELFCLASS64:
   493  		if rela {
   494  			for _, symbol := range symbols {
   495  				binary.Write(ret, e.e.ByteOrder, elf.Rela64{
   496  					Off:  symbol.Off,
   497  					Info: symbol.SymNo<<32 | relt,
   498  				})
   499  			}
   500  			relsz = 24
   501  		} else {
   502  			for _, symbol := range symbols {
   503  				binary.Write(ret, e.e.ByteOrder, elf.Rel64{
   504  					Off:  symbol.Off,
   505  					Info: symbol.SymNo<<32 | relt,
   506  				})
   507  			}
   508  			relsz = 16
   509  		}
   510  	}
   511  	return ret.Bytes(), rela, relsz
   512  }
   513  
   514  func main() {
   515  	doCopy()
   516  	f, err := openElfFile(out)
   517  	if err != nil {
   518  		log.Fatal(err)
   519  	}
   520  
   521  	/*
   522  	        KEEP EXEC (we are not dyn after all)
   523  	        try to put new program headers, dyn, interp into first 4k
   524  	        0  -+-----------------------------------+--
   525  	            | ELF                               |
   526  	            +-----------------------------------+
   527  	            | program headers                   |
   528  	            +-----------------------------------+
   529  	            | interp                            |
   530  	            +-----------------------------------+
   531  	            | dyn stuff                         |
   532  	            +-----------------------------------+
   533  	            | other stuff that needs relocation |
   534  	            +-----------------------------------+-- ensure mapping until here
   535  	            +-----------------------------------+
   536  	   entry -> | Everything else (e.g., text)      |
   537  	            +-----------------------------------+
   538  	            | .shstrtab                         |
   539  	            +-----------------------------------+
   540  	            | Section headers                   |
   541  	            +-----------------------------------+
   542  	*/
   543  
   544  	// First some sanity checks - and checks if we can do our meddling, after all we don't support everything in this POC
   545  
   546  	if f.e.Type != elf.ET_EXEC {
   547  		log.Panic("only static binaries not using an interp supported")
   548  	}
   549  
   550  	var base uint64
   551  	var baseProg int
   552  
   553  	for i, prog := range f.e.Progs {
   554  		if prog.Type == elf.PT_INTERP || prog.Type == elf.PT_DYNAMIC {
   555  			log.Panic("only static binaries not using an interp supported")
   556  		}
   557  		if prog.Type == elf.PT_LOAD {
   558  			if base == 0 {
   559  				base = prog.Vaddr
   560  				baseProg = i
   561  			} else if prog.Vaddr < base {
   562  				base = prog.Vaddr
   563  				baseProg = i
   564  			}
   565  		}
   566  	}
   567  
   568  	if uint64(f.phoff+f.phentsize*uint64(len(f.e.Progs))) > f.e.Entry {
   569  		log.Panic("Not enough space before entry point")
   570  	}
   571  
   572  	interpProg := len(f.e.Progs)
   573  
   574  	f.e.Progs = append(f.e.Progs, &elf.Prog{
   575  		ProgHeader: elf.ProgHeader{
   576  			Type:   elf.PT_INTERP,
   577  			Flags:  elf.PF_R,
   578  			Off:    0, // fill later
   579  			Vaddr:  0, // fill later
   580  			Paddr:  0, // fill later
   581  			Filesz: 0, // fill later
   582  			Memsz:  0, // fill later
   583  			Align:  1,
   584  		}})
   585  
   586  	dynsecProg := len(f.e.Progs)
   587  
   588  	f.e.Progs = append(f.e.Progs, &elf.Prog{
   589  		ProgHeader: elf.ProgHeader{
   590  			Type:   elf.PT_DYNAMIC,
   591  			Flags:  elf.PF_R | elf.PF_W,
   592  			Off:    0, // fill later
   593  			Vaddr:  0, // fill later
   594  			Paddr:  0, // fill later
   595  			Filesz: 0, // fill later
   596  			Memsz:  0, // fill later
   597  			Align:  8,
   598  		}})
   599  
   600  	interpPos := f.phoff + f.phentsize*uint64(len(f.e.Progs))
   601  	interpB := append([]byte(interp), 0)
   602  	interpLen := uint64(len(interpB))
   603  
   604  	f.e.Progs[interpProg].Off = interpPos
   605  	f.e.Progs[interpProg].Vaddr = interpPos + base
   606  	f.e.Progs[interpProg].Paddr = interpPos + base
   607  	f.e.Progs[interpProg].Filesz = interpLen
   608  	f.e.Progs[interpProg].Memsz = interpLen
   609  
   610  	hashPos := interpPos + interpLen
   611  	hashPos += padding(hashPos, 8)
   612  	hash := make([]byte, 8*4) // Empty 64bit DT_HASH
   613  	hashLen := uint64(len(hash))
   614  
   615  	var relList []RelSymbol
   616  
   617  	var symsection int
   618  
   619  	symbolList, err := f.e.Symbols()
   620  	if err != nil {
   621  		log.Fatal(err)
   622  	}
   623  
   624  	var symdefs []DynSymbol
   625  
   626  	symdefs = append(symdefs, DynSymbol{
   627  		Name:    "",
   628  		Value:   0,
   629  		Size:    0,
   630  		Bind:    elf.STB_LOCAL,
   631  		Type:    elf.STT_NOTYPE,
   632  		Vis:     elf.STV_DEFAULT,
   633  		Section: int(elf.SHN_UNDEF),
   634  	})
   635  
   636  	for _, sym := range symbolList {
   637  		if dynsym, ok := relocations[sym.Name]; ok {
   638  			symsection = int(sym.Section)
   639  			relList = append(relList, RelSymbol{
   640  				Off:   sym.Value,
   641  				SymNo: uint64(len(symdefs)),
   642  			})
   643  			symdefs = append(symdefs, DynSymbol{
   644  				Name:    dynsym,
   645  				Value:   0,
   646  				Size:    0,
   647  				Bind:    elf.STB_GLOBAL,
   648  				Type:    elf.STT_FUNC,
   649  				Vis:     elf.STV_DEFAULT,
   650  				Section: int(elf.SHN_UNDEF),
   651  			})
   652  		}
   653  	}
   654  
   655  	dynsym, dynstr := f.makeDynsym(symdefs)
   656  
   657  	var libOffsets []uint64
   658  
   659  	for _, l := range libs {
   660  		libOffsets = append(libOffsets, uint64(len(dynstr)))
   661  		dynstr = append(dynstr, []byte(l)...)
   662  		dynstr = append(dynstr, 0)
   663  	}
   664  
   665  	dynsymLocal := 0
   666  	dynstrPos := hashPos + hashLen
   667  	dynstrLen := uint64(len(dynstr))
   668  
   669  	dynsymPos := dynstrPos + dynstrLen
   670  	dynsymPos += padding(dynsymPos, 8)
   671  	dynsymLen := uint64(len(dynsym))
   672  
   673  	// TODO: DT_BIND_NOW?
   674  
   675  	dynrel, rela, relsz := f.makeDynRel(relList)
   676  	dynrelPos := dynsymPos + dynsymLen
   677  	dynrelPos += padding(dynrelPos, 8)
   678  	dynrelLen := uint64(len(dynrel))
   679  
   680  	var dynsecs []Dyn
   681  	for _, offset := range libOffsets {
   682  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_NEEDED, Val: uint64(offset)})
   683  	}
   684  
   685  	if rela {
   686  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_RELA, Val: uint64(base + dynrelPos)})
   687  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_RELASZ, Val: uint64(dynrelLen)})
   688  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_RELAENT, Val: uint64(relsz)})
   689  	} else {
   690  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_REL, Val: uint64(base + dynrelPos)})
   691  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_RELSZ, Val: uint64(dynrelLen)})
   692  		dynsecs = append(dynsecs, Dyn{Tag: elf.DT_RELENT, Val: uint64(relsz)})
   693  	}
   694  
   695  	dynsecs = append(dynsecs, []Dyn{
   696  		{Tag: elf.DT_STRTAB, Val: base + dynstrPos},
   697  		{Tag: elf.DT_STRSZ, Val: dynstrLen},
   698  		{Tag: elf.DT_SYMTAB, Val: base + dynsymPos},
   699  		{Tag: elf.DT_SYMENT, Val: dynsymLen},
   700  		{Tag: elf.DT_HASH, Val: hashPos + base},
   701  		{Tag: elf.DT_NULL, Val: 0},
   702  	}...)
   703  
   704  	dynsec := f.makeDynsec(dynsecs)
   705  	dynsecPos := dynrelPos + dynrelLen
   706  	dynsecPos += padding(dynsecPos, 8)
   707  	dynsecLen := uint64(len(dynsec))
   708  
   709  	f.e.Progs[dynsecProg].Off = dynsecPos
   710  	f.e.Progs[dynsecProg].Vaddr = dynsecPos + base
   711  	f.e.Progs[dynsecProg].Paddr = dynsecPos + base
   712  	f.e.Progs[dynsecProg].Filesz = dynsecLen
   713  	f.e.Progs[dynsecProg].Memsz = dynsecLen
   714  
   715  	afterDynsec := dynsecPos + dynsecLen
   716  
   717  	relPos := afterDynsec
   718  	var torelocate []*elf.Section
   719  	relocated := make(map[int]bool)
   720  
   721  	for {
   722  		var newRelocate []*elf.Section
   723  		for i, sec := range f.e.Sections {
   724  			if sec.Type == elf.SHT_NULL {
   725  				continue
   726  			}
   727  			if sec.Offset < relPos && !relocated[i] {
   728  				newRelocate = append(newRelocate, sec)
   729  				relocated[i] = true
   730  			}
   731  		}
   732  		if len(newRelocate) == 0 {
   733  			break
   734  		}
   735  		torelocate = append(torelocate, newRelocate...)
   736  
   737  		sort.Slice(torelocate, func(i, j int) bool { return torelocate[i].Offset < torelocate[j].Offset })
   738  		relPos = afterDynsec
   739  		for _, sec := range torelocate {
   740  			relPos += sec.Size
   741  			if sec.Addralign > 1 {
   742  				relPos += padding(relPos, sec.Addralign)
   743  			}
   744  		}
   745  	}
   746  
   747  	for _, sec := range torelocate {
   748  		data := make([]byte, sec.Size)
   749  		if _, err := f.f.ReadAt(data, int64(sec.Offset)); err != nil {
   750  			log.Fatal(err)
   751  		}
   752  		if sec.Addralign > 1 {
   753  			afterDynsec += padding(afterDynsec, sec.Addralign)
   754  		}
   755  		if err := f.WriteAt(data, afterDynsec); err != nil {
   756  			log.Fatal(err)
   757  		}
   758  		for _, prog := range f.e.Progs {
   759  			if prog.Off == sec.Offset {
   760  				prog.Off = afterDynsec
   761  			}
   762  			if prog.Vaddr == sec.Offset+base {
   763  				prog.Vaddr = afterDynsec + base
   764  				prog.Paddr = afterDynsec + base
   765  			}
   766  		}
   767  
   768  		sec.Addr += afterDynsec - sec.Offset // or base + offset
   769  		sec.Offset, afterDynsec = afterDynsec, afterDynsec+sec.Offset
   770  	}
   771  
   772  	if afterDynsec > f.e.Entry {
   773  		log.Fatal("not enough space before entry point")
   774  	}
   775  
   776  	if f.e.Progs[baseProg].Filesz < afterDynsec {
   777  		f.e.Progs[baseProg].Filesz = afterDynsec
   778  		f.e.Progs[baseProg].Memsz = afterDynsec
   779  	}
   780  
   781  	if err := f.WritePrograms(); err != nil {
   782  		log.Fatal(err)
   783  	}
   784  
   785  	if err := f.WriteAt(interpB, interpPos); err != nil {
   786  		log.Fatal(err)
   787  	}
   788  
   789  	if err := f.WriteAt(dynstr, dynstrPos); err != nil {
   790  		log.Fatal(err)
   791  	}
   792  
   793  	if err := f.WriteAt(dynsym, dynsymPos); err != nil {
   794  		log.Fatal(err)
   795  	}
   796  
   797  	if err := f.WriteAt(dynrel, dynrelPos); err != nil {
   798  		log.Fatal(err)
   799  	}
   800  
   801  	if err := f.WriteAt(dynsec, dynsecPos); err != nil {
   802  		log.Fatal(err)
   803  	}
   804  
   805  	f.e.Sections = append(f.e.Sections, &elf.Section{
   806  		SectionHeader: elf.SectionHeader{
   807  			Name:      ".interp",
   808  			Type:      elf.SHT_PROGBITS,
   809  			Flags:     elf.SHF_ALLOC,
   810  			Addr:      base + interpPos,
   811  			Offset:    interpPos,
   812  			FileSize:  interpLen,
   813  			Addralign: 1,
   814  		}})
   815  
   816  	dynstrI := len(f.e.Sections)
   817  
   818  	f.e.Sections = append(f.e.Sections, &elf.Section{
   819  		SectionHeader: elf.SectionHeader{
   820  			Name:      ".dynstr",
   821  			Type:      elf.SHT_STRTAB,
   822  			Flags:     elf.SHF_ALLOC,
   823  			Addr:      base + dynstrPos,
   824  			Offset:    dynstrPos,
   825  			FileSize:  dynstrLen,
   826  			Addralign: 1,
   827  		}})
   828  
   829  	entSize := uint64(24)
   830  	if f.e.Class == elf.ELFCLASS32 {
   831  		entSize = 16
   832  	}
   833  
   834  	dynsymSec := len(f.e.Sections)
   835  
   836  	f.e.Sections = append(f.e.Sections, &elf.Section{
   837  		SectionHeader: elf.SectionHeader{
   838  			Name:      ".dynsym",
   839  			Type:      elf.SHT_DYNSYM,
   840  			Flags:     elf.SHF_ALLOC,
   841  			Addr:      base + dynsymPos,
   842  			Offset:    dynsymPos,
   843  			FileSize:  dynsymLen,
   844  			Addralign: 8,
   845  			Link:      uint32(dynstrI),
   846  			Entsize:   entSize,
   847  			Info:      uint32(dynsymLocal + 1),
   848  		}})
   849  
   850  	entSize = uint64(16)
   851  	if f.e.Class == elf.ELFCLASS32 {
   852  		entSize = 8
   853  	}
   854  
   855  	f.e.Sections = append(f.e.Sections, &elf.Section{
   856  		SectionHeader: elf.SectionHeader{
   857  			Name:      ".dynamic",
   858  			Type:      elf.SHT_DYNAMIC,
   859  			Flags:     elf.SHF_ALLOC | elf.SHF_WRITE,
   860  			Addr:      base + dynsecPos,
   861  			Offset:    dynsecPos,
   862  			FileSize:  dynsecLen,
   863  			Addralign: 8,
   864  			Link:      uint32(dynstrI),
   865  			Entsize:   entSize,
   866  		}})
   867  
   868  	dynname := ".rel"
   869  	if rela {
   870  		dynname = ".rela"
   871  	}
   872  	dynname += f.e.Sections[symsection].Name
   873  
   874  	shtype := elf.SHT_REL
   875  	if rela {
   876  		shtype = elf.SHT_RELA
   877  	}
   878  
   879  	f.e.Sections = append(f.e.Sections, &elf.Section{
   880  		SectionHeader: elf.SectionHeader{
   881  			Name:      dynname,
   882  			Type:      shtype,
   883  			Flags:     elf.SHF_ALLOC,
   884  			Addr:      base + dynrelPos,
   885  			Offset:    dynrelPos,
   886  			FileSize:  dynrelLen,
   887  			Addralign: 8,
   888  			Link:      uint32(dynsymSec),
   889  			Info:      uint32(symsection),
   890  			Entsize:   relsz,
   891  		}})
   892  
   893  	f.e.Sections = append(f.e.Sections, &elf.Section{
   894  		SectionHeader: elf.SectionHeader{
   895  			Name:      ".hash",
   896  			Type:      elf.SHT_HASH,
   897  			Flags:     elf.SHF_ALLOC,
   898  			Addr:      base + hashPos,
   899  			Offset:    hashPos,
   900  			FileSize:  hashLen,
   901  			Addralign: 8,
   902  			Link:      uint32(dynsymSec),
   903  		}})
   904  
   905  	shoff, err := f.f.Seek(0, io.SeekEnd)
   906  	if err != nil {
   907  		log.Fatal(err)
   908  	}
   909  	f.shoff = uint64(shoff)
   910  
   911  	if err := f.WriteSections(); err != nil {
   912  		log.Fatal(err)
   913  	}
   914  
   915  	f.Close()
   916  }