diff options
| -rw-r--r-- | elf.cpp | 159 | ||||
| -rw-r--r-- | elf.h | 8 | ||||
| -rw-r--r-- | test-elf.cpp | 20 | 
3 files changed, 130 insertions, 57 deletions
| @@ -2,50 +2,82 @@  #include "file.h" +#include <iostream> +  // TODO  //#include <boost/endian/conversion.hpp>  #include <cstring> -// We need at least 4096 bytes aligment. Otherwise we get segfaults at startup -#define PAD 0x1000 +#define PAD  // Helper Functions  namespace { - void AddFileHeader(std::vector<uint8_t>& data, const std::vector<uint8_t>& code) + // On amd64, we need at least 4096 bytes aligment. Otherwise we get segfaults at startup + const size_t PAGE_SIZE = 0x1000; + + // Helper function: returns size with full pages: 0, 4096, ... + size_t paged_size(const std::vector<uint8_t>& data) + { +  return (data.size() + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + } + + void AddFileHeader(std::vector<uint8_t>& elf, const std::vector<uint8_t>& code, const std::vector<uint8_t>& data)   {    Elf::FileHeader fh;  #ifdef PAD -  fh.e_shoff = PAD + code.size() + 17; +  fh.e_shoff = PAGE_SIZE + paged_size(code) + data.size() + 23;  #else -  fh.e_shoff = sizeof(fh) + sizeof(Elf::ProgramHeader) + code.size() + 17; +  fh.e_shoff = sizeof(fh) + sizeof(Elf::ProgramHeader) * 2 + code.size() + data.size() + 23;  #endif -  size_t old_size {data.size()}; -  data.resize(old_size + sizeof(fh)); -  std::memcpy(data.data() + old_size, reinterpret_cast<void*>(&fh), sizeof(fh)); +  size_t old_size {elf.size()}; +  elf.resize(old_size + sizeof(fh)); +  std::memcpy(elf.data() + old_size, reinterpret_cast<void*>(&fh), sizeof(fh));   } - void AddProgramHeader(std::vector<uint8_t>& data, const std::vector<uint8_t>& code) + void AddProgramHeaderCode(std::vector<uint8_t>& elf, const std::vector<uint8_t>& code, const std::vector<uint8_t>& data)   {    Elf::ProgramHeader ph;  #ifdef PAD -  ph.p_offset = PAD; -  ph.p_align = PAD; +  ph.p_offset = PAGE_SIZE; +  ph.p_align = PAGE_SIZE;  #else -  ph.p_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader); +  ph.p_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader) * 2;  #endif    ph.p_filesz = code.size();    ph.p_memsz = code.size(); -  size_t old_size {data.size()}; -  data.resize(old_size + sizeof(ph)); -  std::memcpy(data.data() + old_size, reinterpret_cast<void*>(&ph), sizeof(ph)); +  size_t old_size {elf.size()}; +  elf.resize(old_size + sizeof(ph)); +  std::memcpy(elf.data() + old_size, reinterpret_cast<void*>(&ph), sizeof(ph)); + } + + void AddProgramHeaderData(std::vector<uint8_t>& elf, const std::vector<uint8_t>& code, const std::vector<uint8_t>& data) + { +  Elf::ProgramHeader ph; + +#ifdef PAD +  ph.p_offset = PAGE_SIZE + paged_size(code); +  ph.p_align = PAGE_SIZE; +#else +  ph.p_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader) * 2 + code.size(); +#endif +  ph.p_filesz = data.size(); +  ph.p_memsz = data.size(); + +  ph.p_vaddr = 0x401000 + paged_size(code); +  ph.p_paddr = 0x401000 + paged_size(code); +  ph.p_flags = 6; // RW + +  size_t old_size {elf.size()}; +  elf.resize(old_size + sizeof(ph)); +  std::memcpy(elf.data() + old_size, reinterpret_cast<void*>(&ph), sizeof(ph));   } - void AddSectionHeaderNull(std::vector<uint8_t>& data, const std::vector<uint8_t>& code) + void AddSectionHeaderNull(std::vector<uint8_t>& elf, const std::vector<uint8_t>& code, const std::vector<uint8_t>& data)   {    Elf::SectionHeader sh; @@ -56,12 +88,12 @@ namespace {    sh.sh_addr = 0;    sh.sh_offset = 0; -  size_t old_size {data.size()}; -  data.resize(old_size + sizeof(sh)); -  std::memcpy(data.data() + old_size, reinterpret_cast<void*>(&sh), sizeof(sh)); +  size_t old_size {elf.size()}; +  elf.resize(old_size + sizeof(sh)); +  std::memcpy(elf.data() + old_size, reinterpret_cast<void*>(&sh), sizeof(sh));   } - void AddSectionHeaderText(std::vector<uint8_t>& data, const std::vector<uint8_t>& code) + void AddSectionHeaderText(std::vector<uint8_t>& elf, const std::vector<uint8_t>& code, const std::vector<uint8_t>& data)   {    Elf::SectionHeader sh; @@ -69,73 +101,100 @@ namespace {    sh.sh_size = code.size();    sh.sh_type = 1; // program  #ifdef PAD -  sh.sh_offset = PAD; +  sh.sh_offset = PAGE_SIZE;  #else -  sh.sh_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader); +  sh.sh_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader) * 2;  #endif    sh.sh_addralign = 1; -  size_t old_size {data.size()}; -  data.resize(old_size + sizeof(sh)); -  std::memcpy(data.data() + old_size, reinterpret_cast<void*>(&sh), sizeof(sh)); +  size_t old_size {elf.size()}; +  elf.resize(old_size + sizeof(sh)); +  std::memcpy(elf.data() + old_size, reinterpret_cast<void*>(&sh), sizeof(sh));   } - void AddSectionHeaderSectionNames(std::vector<uint8_t>& data, const std::vector<uint8_t>& code) + void AddSectionHeaderData(std::vector<uint8_t>& elf, const std::vector<uint8_t>& code, const std::vector<uint8_t>& data)   {    Elf::SectionHeader sh;    sh.sh_name = 7; // offset in section -  sh.sh_size = 17; +  sh.sh_size = data.size(); +  sh.sh_type = 1; // program (also data) +#ifdef PAD +  sh.sh_offset = PAGE_SIZE + paged_size(code); +#else +  sh.sh_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader) * 2 + code.size(); +#endif +  sh.sh_addralign = 1; + +  size_t old_size {elf.size()}; +  elf.resize(old_size + sizeof(sh)); +  std::memcpy(elf.data() + old_size, reinterpret_cast<void*>(&sh), sizeof(sh)); + } +  + void AddSectionHeaderSectionNames(std::vector<uint8_t>& elf, const std::vector<uint8_t>& code, const std::vector<uint8_t>& data) + { +  Elf::SectionHeader sh; + +  sh.sh_name = 13; // offset in section +  sh.sh_size = 23;    sh.sh_type = 3; // section names    sh.sh_flags = 0;    sh.sh_addr = 0;  #ifdef PAD -  sh.sh_offset = PAD + code.size(); +  sh.sh_offset = PAGE_SIZE + paged_size(code) + data.size();  #else -  sh.sh_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader) + code.size(); +  sh.sh_offset = sizeof(Elf::FileHeader) + sizeof(Elf::ProgramHeader) * 2 + code.size() + data.size();  #endif    sh.sh_addralign = 1; -  size_t old_size {data.size()}; -  data.resize(old_size + sizeof(sh)); -  std::memcpy(data.data() + old_size, reinterpret_cast<void*>(&sh), sizeof(sh)); +  size_t old_size {elf.size()}; +  elf.resize(old_size + sizeof(sh)); +  std::memcpy(elf.data() + old_size, reinterpret_cast<void*>(&sh), sizeof(sh));   } - void PadUpTo(std::vector<uint8_t>& data, size_t size) + void PadUpTo(std::vector<uint8_t>& elf, size_t size)   { -  if (data.size() < size) { -   data.resize(size); +  if (elf.size() < size) { +   elf.resize(size);    } else     throw std::runtime_error("Padding not possible. Too many bytes already.");   }  } -void Elf::Write(const std::filesystem::path& path, const std::vector<uint8_t>& code) +void Elf::Write(const std::filesystem::path& path, const std::vector<uint8_t>& code, const std::vector<uint8_t>& data)  { - std::vector<uint8_t> data; + std::vector<uint8_t> elf; - AddFileHeader(data, code); - AddProgramHeader(data, code); + AddFileHeader(elf, code, data); + AddProgramHeaderCode(elf, code, data); + AddProgramHeaderData(elf, code, data);  #ifdef PAD - PadUpTo(data, PAD); + PadUpTo(elf, PAGE_SIZE);  #endif - data.insert(data.end(), code.begin(), code.end()); + elf.insert(elf.end(), code.begin(), code.end()); + +#ifdef PAD + PadUpTo(elf, PAGE_SIZE + paged_size(code)); +#endif - std::string section_names("\0.text\0.shstrtab\0", 17); - if (section_names.size() != 17) + elf.insert(elf.end(), data.begin(), data.end()); + + std::string section_names("\0.text\0.data\0.shstrtab\0", 23); + if (section_names.size() != 23)    throw std::runtime_error("Bad size"); - size_t old_size {data.size()}; - data.resize(old_size + section_names.size()); - std::memcpy(data.data() + old_size, section_names.data(), section_names.size()); + size_t old_size {elf.size()}; + elf.resize(old_size + section_names.size()); + std::memcpy(elf.data() + old_size, section_names.data(), section_names.size()); - AddSectionHeaderNull(data, code); - AddSectionHeaderText(data, code); - AddSectionHeaderSectionNames(data, code); + AddSectionHeaderNull(elf, code, data); + AddSectionHeaderText(elf, code, data); + AddSectionHeaderData(elf, code, data); + AddSectionHeaderSectionNames(elf, code, data); - File::setFile(path, data); + File::setFile(path, elf);  }  std::vector<uint8_t> Elf::Read(const std::filesystem::path& path) @@ -42,10 +42,10 @@ struct FileHeader   uint32_t e_flags{};   uint16_t e_ehsize{0x40}; // size of this header   uint16_t e_phentsize{0x38}; // size of program header - uint16_t e_phnum{1}; // 1 program header + uint16_t e_phnum{2}; // program headers: .text, .data   uint16_t e_shentsize{0x40}; // size of section header - uint16_t e_shnum{3}; // number of section headers - uint16_t e_shstrndx{2}; // 1st section header contains section names + uint16_t e_shnum{4}; // number of section headers + uint16_t e_shstrndx{3}; // 1st section header contains section names  };  // Segment @@ -76,7 +76,7 @@ struct SectionHeader  };  #pragma pack(pop) -void Write(const std::filesystem::path& path, const std::vector<uint8_t>&); +void Write(const std::filesystem::path& path, const std::vector<uint8_t>& code, const std::vector<uint8_t>& data);  std::vector<uint8_t> Read(const std::filesystem::path& path);  } diff --git a/test-elf.cpp b/test-elf.cpp index d3fa9a9..46ef267 100644 --- a/test-elf.cpp +++ b/test-elf.cpp @@ -35,7 +35,7 @@ protected:   }   void TearDown(){    std::error_code ec; -  //fs::remove(TempFilename(), ec); +  fs::remove(TempFilename(), ec);   }  }; @@ -44,13 +44,27 @@ TEST_F(ElfTest, read) {  }  #endif -TEST_F(ElfTest, write) { +TEST_F(ElfTest, write_code) {   Elf::Write(TempFilename(),              {              0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, // mov    $0x3c,%rax     # syscall 60              0x48, 0x31, 0xff,                         // xor    %rdi,%rdi      # exit code 0              0x0f, 0x05,                               // syscall -            }); +            }, {}); + + ASSERT_TRUE(fs::exists(TempFilename())); + ASSERT_GT(fs::file_size(TempFilename()), 0); +} + +TEST_F(ElfTest, write_code_data) { + Elf::Write(TempFilename(), +            { +            0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, // mov    $0x3c,%rax     # syscall 60 +            0x48, 0x8b, 0x3c, 0x25, 0x00, 0x20, 0x40, // mov    0x402000,%rdi  # use value from data segment as exit code +            0, +            0x0f, 0x05,                               // syscall +            }, +            {1, 0, 0, 0, 0, 0, 0, 0});   ASSERT_TRUE(fs::exists(TempFilename()));   ASSERT_GT(fs::file_size(TempFilename()), 0); | 
