diff options
Diffstat (limited to 'src/elf_common/elf_reader.h')
| -rw-r--r-- | src/elf_common/elf_reader.h | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/src/elf_common/elf_reader.h b/src/elf_common/elf_reader.h new file mode 100644 index 0000000..8c5c79a --- /dev/null +++ b/src/elf_common/elf_reader.h @@ -0,0 +1,432 @@ + +/** + * A very basic template based ELF reader. It is very common for OS's + * to implement their own ELF ABI. Section and segment headers are most + * commonly kept standard. + * + * Assumes that: + * - Elf_Ehdr is standard. + * - Elf_Shdr is standard. + * - Elf_Phdr is standard. + * - Only one SYMTAB section according to ELF ABI. + * - This system is little endian. If there is a problem with this, + * please let the author know. + * + * What it stores info for: + * - Elf_Ehdr as read from file. + * - vector of Elf_Shdr abstracted as Section. + * - vector of Elf_Phdr abstracted as Segment. + * - index of symbol section. + * - index of dynamic segment. <- TODO + * - index of section header string table section. + * + * Important facts about this reader: + * - Elf_Ehdr, Elf_Shdr, and Elf_Phdr is swapped if ELFDATA2MSB is set. + * This is to facilitate faster header/section/segment handling without + * the user needing to swap them. + * - Section/segment data is not modified by this reader. + * - Any section/segment data must be swapped by the user. + * - Data is only loaded when requested. (see Segment/Section data()) +**/ + +#pragma once + +#include "elf.h" + +#include <idaldr.h> // TODO: do not depend on this +#include <vector> + +static void printhex(const unsigned char *data, size_t size) +{ + msg("00000000 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); + for (size_t i = 0; i < size; i += 16) + { + msg("%08x ", i); + msg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + data[i + 0], data[i + 1], data[i + 2], data[i + 3], data[i + 4], + data[i + 5], data[i + 6], data[i + 7], data[i + 8], data[i + 9], + data[i + 10], data[i + 11], data[i + 12], data[i + 13], data[i + 14], + data[i + 15]); + } +} + +template <typename T> +void swap(T &buf) { + unsigned char &pbuf = reinterpret_cast<unsigned char &>(buf); + std::reverse(&pbuf, &pbuf + sizeof(T)); +} + +class elf32 { +public: + typedef Elf32_Ehdr Ehdr; + typedef Elf32_Shdr Shdr; + typedef Elf32_Phdr Phdr; + typedef Elf32_Sym Sym; + typedef Elf32_Word Word; + typedef Elf32_Addr Addr; +}; + +class elf64 { +public: + typedef Elf64_Ehdr Ehdr; + typedef Elf64_Shdr Shdr; + typedef Elf64_Phdr Phdr; + typedef Elf64_Sym Sym; + typedef Elf64_Word Word; + typedef Elf64_Addr Addr; +}; + +template <class Elf> +class Segment + : public Elf::Phdr { + linput_t *m_reader; + std::vector<char> m_data; + +public: + Segment() {} + + Segment(linput_t *li) + : m_reader(li) + { + } + + char *data() + { + if (m_data.empty()) + { + m_data.resize(this->p_filesz); + qlseek(m_reader, this->p_offset); + qlread(m_reader, (void *)m_data.data(), this->p_filesz); + } + + return m_data.data(); + } + + void setData(const char *data, size_t length) + { + m_data.assign(data, length); + } + + void setReader(linput_t *li) + { + this->m_reader = li; + } +}; + +template <class Elf> +class Section + : public Elf::Shdr { + linput_t *m_reader; + std::vector<char> m_data; // TODO: switch to std::vector + +public: + Section() {} + + char *data() + { + if (m_data.empty()) { + m_data.resize(this->sh_size); + if (qlseek(m_reader, this->sh_offset) != this->sh_offset) + msg("Failed to seek to data.\n"); + if (qlread(m_reader, (void *)m_data.data(), this->sh_size) == -1) + msg("Failed to read data.\n"); + } + + return m_data.data(); + } + + void setData(const char *data, size_t length) + { + m_data.assign(data, length); + } + + void setReader(linput_t *li) + { + this->m_reader = li; + } + + uint32 getNumEntries() const + { + if (this->sh_entsize != 0) + return this->sh_size / this->sh_entsize; + return 0; + } + + uint32 getSize() const + { + return m_data.size(); + } +}; + +template < + class Elf // Elf type + /*TODO: class reader*/ // reader interface + /*TODO: class logger*/ // log file interface + > +class elf_reader { + typename Elf::Ehdr m_header; + std::vector< Segment<Elf> > m_segments; + std::vector< Section<Elf> > m_sections; + Section<Elf> *m_symbolTableSection; + Section<Elf> *m_sectionStringTable; + + linput_t *m_reader; + +public: + elf_reader(linput_t *li) + : m_reader(li) + { + m_symbolTableSection = NULL; + m_sectionStringTable = NULL; + } + + void read() { + readHeader(); + readSegments(); + readSections(); + } + + void print() { + printHeader(); + printSegment(); + printSections(); + printSymbols(); + } + + bool verifyHeader() { + readHeader(); + + if (m_header.e_ident[EI_MAG0] == ELFMAG0 && + m_header.e_ident[EI_MAG1] == ELFMAG1 && + m_header.e_ident[EI_MAG2] == ELFMAG2 && + m_header.e_ident[EI_MAG3] == ELFMAG3) { + return true; + } + + return false; + } + + linput_t *getReader() const + { return this->m_reader; } + + uchar osabi() const + { return m_header.e_ident[EI_OSABI]; } + + uchar bitsize() const + { return m_header.e_ident[EI_CLASS]; } + + uchar endian() const + { return m_header.e_ident[EI_DATA]; } + + typename Elf::Word type() const + { return m_header.e_type; } + + typename Elf::Word machine() const + { return m_header.e_machine; } + + typename Elf::Addr entry() const + { return m_header.e_entry; } + + typename Elf::Word flags() const + { return m_header.e_flags; } + + uint32_t getNumSegments() const + { return m_segments.size(); } + + uint32_t getNumSections() const + { return m_sections.size(); } + + std::vector< Segment<Elf> > &getSegments() + { return m_segments; } + + std::vector< Section<Elf> > &getSections() + { return m_sections; } + + Section<Elf> *getSectionStringTable() const + { return m_sectionStringTable; } + + Section<Elf> *getSymbolsSection() const + { return m_symbolTableSection; } + + uint32_t getNumSymbols() const + { return m_symbolTableSection->getNumEntries(); } + + typename Elf::Sym *getSymbols() const + { return (typename Elf::Sym *)m_symbolTableSection->data(); } + + Section<Elf> *getSectionByName(const char *name) + { + const char *strTab = m_sectionStringTable->data(); + for (auto §ion : m_sections) { + if (strcmp(&strTab[section.sh_name], name) == 0) + return §ion; + } + return NULL; + } + + uchar getAlignment(typename Elf::Word align) + { + switch (align) { + case 0x1: return saRelByte; + case 0x2: return saRelWord; + case 0x4: return saRelDble; + case 0x8: return saRelQword; + case 0x40: return saRel64Bytes; + case 0x80: return saRel128Bytes; + case 0x100: return saRelPage; + case 0x200: return saRel512Bytes; + case 0x400: return saRel2048Bytes; + case 0x1000: return saRel4K; + default: return saRelDble; + } + } + +private: + void readHeader() { + //msg("Reading header.\n"); + + qlseek(m_reader, 0); + qlread(m_reader, &m_header, sizeof(m_header)); + + if (m_header.e_ident[EI_DATA] == ELFDATA2MSB) { + swap(m_header.e_type); + swap(m_header.e_machine); + swap(m_header.e_version); + swap(m_header.e_entry); + swap(m_header.e_phoff); + swap(m_header.e_shoff); + swap(m_header.e_flags); + swap(m_header.e_ehsize); + swap(m_header.e_phentsize); + swap(m_header.e_phnum); + swap(m_header.e_shentsize); + swap(m_header.e_shnum); + swap(m_header.e_shstrndx); + } + + //printHeader(); + } + + void readSegments() { + if (m_header.e_phnum > 0) { + //msg("Reading segments.\n"); + m_segments.resize(m_header.e_phnum); + + qlseek(m_reader, m_header.e_phoff); + + for (auto &segment : m_segments) { + qlread(m_reader, (typename Elf::Phdr *)&segment, m_header.e_phentsize); + + if (m_header.e_ident[EI_DATA] == ELFDATA2MSB) { + swap(segment.p_type); + swap(segment.p_flags); + swap(segment.p_offset); + swap(segment.p_vaddr); + swap(segment.p_paddr); + swap(segment.p_filesz); + swap(segment.p_memsz); + swap(segment.p_align); + } + + segment.setReader(m_reader); + } + + //printSegments(); + } + } + + void readSections() { + if (m_header.e_shnum > 0) { + //msg("Reading sections...\n"); + + m_sections.resize(m_header.e_shnum); + + size_t index = 0; + for (auto §ion : m_sections) { + qlseek(m_reader, m_header.e_shoff + index * m_header.e_shentsize); + qlread(m_reader, (typename Elf::Shdr *)§ion, m_header.e_shentsize); + + if (m_header.e_ident[EI_DATA] == ELFDATA2MSB) { + swap(section.sh_name); + swap(section.sh_type); + swap(section.sh_flags); + swap(section.sh_addr); + swap(section.sh_offset); + swap(section.sh_size); + swap(section.sh_link); + swap(section.sh_info); + swap(section.sh_addralign); + swap(section.sh_entsize); + } + + section.setReader(m_reader); + + // only one symbol table per ELF + if (section.sh_type == SHT_SYMTAB) + m_symbolTableSection = §ion; + + ++index; + } + + if (m_header.e_shstrndx != SHN_UNDEF && + m_sections[m_header.e_shstrndx].sh_type == SHT_STRTAB) + m_sectionStringTable = &m_sections[m_header.e_shstrndx]; + + //printSections(); + } + } + + void printHeader() { + msg("Elf Header:\n"); + msg(" e_ident "); + for (int i = 0; i < EI_NIDENT; i++) + msg(" %02x", m_header.e_ident[i]); + msg("\n"); + msg(" e_type %04x\n", m_header.e_type); + msg(" e_machine %04x\n", m_header.e_machine); + msg(" e_version %08x\n", m_header.e_version); + msg(" e_entry %08x\n", m_header.e_entry); + msg(" e_phoff %08x\n", m_header.e_phoff); + msg(" e_shoff %08x\n", m_header.e_shoff); + msg(" e_flags %08x\n", m_header.e_flags); + msg(" e_ehsize %d\n", m_header.e_ehsize); + msg(" e_phentsize %d\n", m_header.e_phentsize); + msg(" e_phnum %d\n", m_header.e_phnum); + msg(" e_shentsize %d\n", m_header.e_shentsize); + msg(" e_shnum %d\n", m_header.e_shnum); + msg(" e_shstrndx %d\n", m_header.e_shstrndx); + } + + void printSegments() { + size_t index = 0; + for (auto &segment : m_segments) { + msg("Program Header #%d\n", index); + msg(" p_type %08x\n", segment.p_type); + msg(" p_offset %08x\n", segment.p_offset); + msg(" p_vaddr %08x\n", segment.p_vaddr); + msg(" p_paddr %08x\n", segment.p_paddr); + msg(" p_filesz %08x\n", segment.p_filesz); + msg(" p_memsz %08x\n", segment.p_memsz); + msg(" p_flags %08x\n", segment.p_flags); + msg(" p_align %08x\n", segment.p_align); + ++index; + } + } + + void printSections() { + size_t index = 0; + for (auto §ion : m_sections) { + msg("Section Header #%d\n", index); + msg(" sh_name %08x\n", section.sh_name); + msg(" sh_type %08x\n", section.sh_type); + msg(" sh_addr %08x\n", section.sh_addr); + msg(" sh_offset %08x\n", section.sh_offset); + msg(" sh_size %08x\n", section.sh_size); + msg(" sh_link %08x\n", section.sh_link); + msg(" sh_info %08x\n", section.sh_info); + msg(" sh_addralign %08x\n", section.sh_addralign); + msg(" sh_entsize %08x\n", section.sh_entsize); + ++index; + } + } +};
\ No newline at end of file |
