mirror of
https://github.com/Binject/debug
synced 2026-06-08 10:28:33 +00:00
193 lines
5.4 KiB
Go
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
|
|
}
|