Files

193 lines
5.4 KiB
Go

package elf
import (
"bufio"
"encoding/binary"
"io/ioutil"
"log"
"os"
"sort"
)
// Write - Writes an *elf.File to disk
func (elfFile *File) Write(destFile string) error {
bytesWritten := uint64(0)
f, err := os.Create(destFile)
if err != nil {
return err
}
defer f.Close()
w := bufio.NewWriter(f)
// Write Elf Magic
w.WriteByte('\x7f')
w.WriteByte('E')
w.WriteByte('L')
w.WriteByte('F')
bytesWritten += 4
// ident[EI_CLASS]
w.WriteByte(byte(elfFile.Class))
// ident[EI_DATA]
w.WriteByte(byte(elfFile.Data))
// ident[EI_VERSION]
w.WriteByte(byte(elfFile.Version))
// ident[EI_OSABI]
w.WriteByte(byte(elfFile.OSABI))
// ident[EI_ABIVERSION]
w.WriteByte(byte(elfFile.ABIVersion))
// ident[EI_PAD] ( 7 bytes )
w.Write([]byte{0, 0, 0, 0, 0, 0, 0})
bytesWritten += 12
// Type
binary.Write(w, elfFile.ByteOrder, uint16(elfFile.Type))
// Machine
binary.Write(w, elfFile.ByteOrder, uint16(elfFile.Machine))
// Version
binary.Write(w, elfFile.ByteOrder, uint32(elfFile.Version))
bytesWritten += 8
phsize := 0
switch elfFile.Class {
case ELFCLASS32:
phsize = 0x20
// Entry 32
binary.Write(w, elfFile.ByteOrder, uint32(elfFile.Entry))
// PH Offset 32
binary.Write(w, elfFile.ByteOrder, uint32(0x34))
// SH Offset 32 // 0x20 0x28 4 8 e_shoff Points to the start of the section header table.
binary.Write(w, elfFile.ByteOrder, int32(elfFile.FileHeader.SHTOffset))
// Flags
binary.Write(w, elfFile.ByteOrder, uint32(0)) // todo
// EH Size
binary.Write(w, elfFile.ByteOrder, uint16(52))
// PH Size // 0x2A 0x36 2 e_phentsize Contains the size of a program header table entry.
binary.Write(w, elfFile.ByteOrder, uint16(phsize))
// PH Num // 0x2C 0x38 2 e_phnum Contains the number of entries in the program header table.
binary.Write(w, elfFile.ByteOrder, uint16(len(elfFile.Progs)))
// SH Size // 0x2E 0x3A 2 e_shentsize Contains the size of a section header table entry.
binary.Write(w, elfFile.ByteOrder, uint16(0x28))
bytesWritten += 24
case ELFCLASS64:
phsize = 0x38
// Entry 64
binary.Write(w, elfFile.ByteOrder, uint64(elfFile.Entry))
// PH Offset 64
binary.Write(w, elfFile.ByteOrder, uint64(0x40))
// SH Offset 64 // 0x20 0x28 4 8 e_shoff Points to the start of the section header table.
binary.Write(w, elfFile.ByteOrder, int64(elfFile.FileHeader.SHTOffset))
// Flags
binary.Write(w, elfFile.ByteOrder, uint32(0)) // I think right?
// EH Size
binary.Write(w, elfFile.ByteOrder, uint16(64))
// PH Size // 0x2A 0x36 2 e_phentsize Contains the size of a program header table entry.
binary.Write(w, elfFile.ByteOrder, uint16(phsize))
// PH Num // 0x2C 0x38 2 e_phnum Contains the number of entries in the program header table.
binary.Write(w, elfFile.ByteOrder, uint16(len(elfFile.Progs)))
// SH Size // 0x2E 0x3A 2 e_shentsize Contains the size of a section header table entry.
binary.Write(w, elfFile.ByteOrder, uint16(0x40))
bytesWritten += 36
}
// SH Num // 0x30 0x3C 2 e_shnum Contains the number of entries in the section header table.
binary.Write(w, elfFile.ByteOrder, uint16(len(elfFile.Sections)))
// SH Str Ndx // 0x32 0x3E 2 e_shstrndx Contains index of the section header table entry that contains the section names.
binary.Write(w, elfFile.ByteOrder, uint16(elfFile.ShStrIndex))
bytesWritten += 4
// Program Header
for _, p := range elfFile.Progs {
// Type (segment)
binary.Write(w, elfFile.ByteOrder, uint32(p.Type))
bytesWritten += 4
switch elfFile.Class {
case ELFCLASS32:
// Offset of Segment in File
binary.Write(w, elfFile.ByteOrder, uint32(p.Off))
// Vaddr
binary.Write(w, elfFile.ByteOrder, uint32(p.Vaddr))
// Paddr
binary.Write(w, elfFile.ByteOrder, uint32(p.Paddr))
// File Size
binary.Write(w, elfFile.ByteOrder, uint32(p.Filesz))
// Memory Size
binary.Write(w, elfFile.ByteOrder, uint32(p.Memsz))
// Flags (segment)
binary.Write(w, elfFile.ByteOrder, uint32(p.Flags))
// Alignment
binary.Write(w, elfFile.ByteOrder, uint32(p.Align))
bytesWritten += 28
case ELFCLASS64:
// Flags (segment)
binary.Write(w, elfFile.ByteOrder, uint32(p.Flags))
// Offset of Segment in File
binary.Write(w, elfFile.ByteOrder, uint64(p.Off))
// Vaddr
binary.Write(w, elfFile.ByteOrder, uint64(p.Vaddr))
// Paddr
binary.Write(w, elfFile.ByteOrder, uint64(p.Paddr))
// File Size
binary.Write(w, elfFile.ByteOrder, uint64(p.Filesz))
// Memory Size
binary.Write(w, elfFile.ByteOrder, uint64(p.Memsz))
// Alignment
binary.Write(w, elfFile.ByteOrder, uint64(p.Align))
bytesWritten += 52
}
}
sortedSections := elfFile.Sections[:]
sort.Slice(sortedSections, func(a, b int) bool { return elfFile.Sections[a].Offset < elfFile.Sections[b].Offset })
for _, s := range sortedSections {
if s.Type == SHT_NULL {
continue
}
if bytesWritten > s.Offset {
log.Printf("Overlapping Sections in Generated Elf: %+v\n", s.Name)
continue
}
if bytesWritten < s.Offset {
pad := make([]byte, s.Offset-bytesWritten)
w.Write(pad)
bytesWritten += uint64(len(pad))
}
section, err := ioutil.ReadAll(s.Open())
if err != nil {
return err
}
binary.Write(w, elfFile.ByteOrder, section)
bytesWritten += uint64(len(section))
if len(elfFile.Insertion) > 0 && s.Size-uint64(len(section)) == uint64(len(elfFile.Insertion)) {
binary.Write(w, elfFile.ByteOrder, elfFile.Insertion)
bytesWritten += uint64(len(elfFile.Insertion))
}
w.Flush()
}
w.Flush()
return nil
}