diff --git a/loader/elf.cpp b/loader/elf.cpp index 217e3ef..a8085cb 100644 --- a/loader/elf.cpp +++ b/loader/elf.cpp @@ -18,6 +18,8 @@ static const uint32_t DT_SYMTAB = 6; static const uint32_t DT_STRSZ = 10; static const uint32_t SHT_SYMTAB = 2; static const uint32_t SHT_DYNSYM = 11; +static const uint32_t SHT_RELA = 4; +static const uint32_t SHT_REL = 9; ELFLoader::ELFLoader() : m_arch(Arch::X64), m_entry(0), @@ -149,9 +151,11 @@ bool ELFLoader::parseHeader() uint64_t pfilesz = r64(m_data, off + 32); uint64_t pmemsz = r64(m_data, off + 40); - if (ptype == PT_LOAD && (pflags & 1)) + if (ptype == PT_LOAD) { - m_exec_ranges.push_back({pvaddr, pvaddr + pmemsz}); + m_file_map.push_back({poffset, pvaddr, pmemsz}); + if (pflags & 1) + m_exec_ranges.push_back({pvaddr, pvaddr + pmemsz}); } if (ptype == PT_DYNAMIC) @@ -167,7 +171,7 @@ bool ELFLoader::parseHeader() uint64_t val = r64(m_data, j + 8); if (tag == DT_NULL) break; - if (tag == DT_NEEDED && val) + if (tag == DT_NEEDED && val && m_needed_libs.empty()) { uint64_t strtab = 0; for (size_t k = dyn_off; k + 16 <= end; k += 16) @@ -181,14 +185,8 @@ bool ELFLoader::parseHeader() size_t name_off = strtab + val; if (name_off < m_data.size()) { - string lib; for (size_t c = name_off; c < m_data.size() && m_data[c]; c++) - lib += (char)m_data[c]; - ImportEntry e; - e.address = 0; - e.name = lib; - e.library = lib; - m_imports.push_back(e); + m_needed_libs += (char)m_data[c]; } } } @@ -202,67 +200,153 @@ bool ELFLoader::parseHeader() } } + struct SectionInfo { + uint32_t type; + uint64_t addr; + uint64_t offset; + uint64_t size; + uint32_t link; + uint64_t entsize; + uint32_t name_idx; + }; + vector sections(shnum); + uint64_t shstrtab_off = 0; for (uint16_t i = 0; i < shnum; i++) { size_t off = shoff + i * 64; if (off + 64 > m_data.size()) break; - uint32_t stype = r32(m_data, off + 4); + sections[i].type = r32(m_data, off + 4); + sections[i].addr = r64(m_data, off + 16); + sections[i].offset = r64(m_data, off + 24); + sections[i].size = r64(m_data, off + 32); + sections[i].link = r32(m_data, off + 40); + sections[i].entsize = r64(m_data, off + 56); + sections[i].name_idx = r32(m_data, off); + if (i == shstrndx) shstrtab_off = sections[i].offset; + } - if (stype == SHT_DYNSYM || stype == SHT_SYMTAB) + auto sectionName = [&](uint32_t idx) -> string { + if (!shstrtab_off) return ""; + size_t pos = shstrtab_off + idx; + string s; + for (; pos < m_data.size() && m_data[pos]; pos++) + s += (char)m_data[pos]; + return s; + }; + + vector strtab_offsets(shnum, 0); + for (uint16_t i = 0; i < shnum; i++) + { + if (sections[i].type == SHT_SYMTAB || sections[i].type == SHT_DYNSYM) { - uint64_t sym_off = r64(m_data, off + 24); - uint64_t sym_sz = r64(m_data, off + 32); - uint32_t link = r32(m_data, off + 40); - uint64_t entsize = r64(m_data, off + 56); - if (entsize == 0) entsize = 24; + uint32_t link = sections[i].link; + if (link < shnum) + strtab_offsets[i] = sections[link].offset; + } + } - uint64_t strtab_off = 0; - uint64_t strtab_sz = 0; - for (uint16_t k = 0; k < shnum; k++) + for (uint16_t i = 0; i < shnum; i++) + { + if (sections[i].type != SHT_SYMTAB && sections[i].type != SHT_DYNSYM) + continue; + + uint64_t sym_off = sections[i].offset; + uint64_t sym_sz = sections[i].size; + uint64_t entsize = sections[i].entsize ? sections[i].entsize : 24; + uint64_t str_off = strtab_offsets[i]; + + size_t nsym = sym_sz / entsize; + for (size_t j = 0; j < nsym; j++) + { + size_t ent = sym_off + j * entsize; + if (ent + 24 > m_data.size()) break; + uint32_t sym_name_off = r32(m_data, ent); + uint8_t sym_info = m_data[ent + 4]; + uint8_t sym_other = m_data[ent + 5]; + uint16_t sym_shndx = r16(m_data, ent + 6); + uint64_t sym_val = r64(m_data, ent + 8); + uint64_t sym_size = r64(m_data, ent + 16); + + uint8_t sym_type = sym_info & 0xF; + uint8_t sym_bind = sym_info >> 4; + + if (sym_type != 2) continue; + if (!sym_name_off || !str_off) continue; + + size_t name_pos = str_off + sym_name_off; + if (name_pos >= m_data.size()) continue; + + string sym_name; + for (size_t c = name_pos; c < m_data.size() && m_data[c]; c++) + sym_name += (char)m_data[c]; + if (sym_name.empty()) continue; + + if (sym_shndx != 0 && sym_val) { - size_t soff = shoff + k * 64; - if (soff + 64 > m_data.size()) break; - if (r32(m_data, soff + 4) == SHT_SYMTAB || r32(m_data, soff + 4) == SHT_DYNSYM) - continue; - if ((uint32_t)k == link) - { - strtab_off = r64(m_data, soff + 24); - strtab_sz = r64(m_data, soff + 32); - break; - } - } - - size_t nsym = sym_sz / entsize; - for (size_t j = 0; j < nsym; j++) - { - size_t sym_ent = sym_off + j * entsize; - if (sym_ent + 16 > m_data.size()) break; - uint32_t sym_name_off = r32(m_data, sym_ent); - uint8_t sym_info = m_data[sym_ent + 4]; - uint64_t sym_val = r64(m_data, sym_ent + 8); - - uint8_t sym_type = sym_info & 0xF; - uint8_t sym_bind = sym_info >> 4; - - if (sym_val && sym_type == 2 && sym_name_off && strtab_off) - { - size_t name_pos = strtab_off + sym_name_off; - if (name_pos < m_data.size()) - { - string sym_name; - for (size_t c = name_pos; c < m_data.size() && m_data[c]; c++) - sym_name += (char)m_data[c]; - if (!sym_name.empty()) - { - m_symbols[sym_val] = sym_name; - if (sym_bind == 0) m_exports.push_back({sym_val, sym_name}); - } - } - } + m_symbols[sym_val] = sym_name; + if (sym_bind == 1) + m_exports.push_back({sym_val, sym_name}); } } + } - if (stype == SHT_DYNSYM) break; + for (uint16_t i = 0; i < shnum; i++) + { + string sname = sectionName(sections[i].name_idx); + if (sections[i].type != SHT_RELA && sname != ".rela.plt" && sname != ".rela.dyn") + continue; + + uint64_t rela_off = sections[i].offset; + uint64_t rela_sz = sections[i].size; + size_t nrela = rela_sz / 24; + if (nrela == 0) continue; + + uint32_t symtab_link = sections[i].link; + if (symtab_link >= shnum) continue; + + uint64_t sym_off = sections[symtab_link].offset; + uint64_t sym_sz = sections[symtab_link].size; + uint64_t str_off2 = 0; + uint32_t str_link = sections[symtab_link].link; + if (str_link < shnum) str_off2 = sections[str_link].offset; + uint64_t sym_entsize = sections[symtab_link].entsize ? sections[symtab_link].entsize : 24; + + string lib_name = m_needed_libs; + + for (size_t j = 0; j < nrela; j++) + { + size_t ent = rela_off + j * 24; + if (ent + 24 > m_data.size()) break; + uint64_t r_offset = r64(m_data, ent); + uint64_t r_info = r64(m_data, ent + 8); + uint32_t sym_idx = (uint32_t)(r_info >> 32); + + if (!sym_idx) continue; + + size_t sym_ent = sym_off + sym_idx * sym_entsize; + if (sym_ent + 24 > m_data.size()) continue; + uint32_t func_name_off = r32(m_data, sym_ent); + if (!func_name_off || !str_off2) continue; + + size_t fn_pos = str_off2 + func_name_off; + if (fn_pos >= m_data.size()) continue; + + string func_name; + for (size_t c = fn_pos; c < m_data.size() && m_data[c]; c++) + func_name += (char)m_data[c]; + if (func_name.empty()) continue; + + bool dup = false; + for (const auto& imp : m_imports) + if (imp.address == r_offset) { dup = true; break; } + if (dup) continue; + + ImportEntry e; + e.address = r_offset; + e.name = func_name; + e.library = lib_name; + m_imports.push_back(e); + } } } else @@ -290,30 +374,21 @@ bool ELFLoader::parseSymbols() vector ELFLoader::readBytes(addr_t vaddr, size_t size) const { - vector result; - for (const auto& r : m_exec_ranges) + for (const auto& fmap : m_file_map) { - if (vaddr >= r.first && vaddr < r.second) + addr_t seg_vaddr = get<1>(fmap); + uint64_t seg_size = get<2>(fmap); + if (vaddr >= seg_vaddr && vaddr < seg_vaddr + seg_size) { - addr_t offset = vaddr; - for (const auto& r2 : m_exec_ranges) - { - if (offset >= r2.first && offset < r2.second) - { - addr_t file_off = 0; - size_t max_read = min(size, (size_t)(r2.second - offset)); - size_t copy_start = offset - r2.first; - if (copy_start < m_data.size()) - { - size_t to_copy = min(max_read, m_data.size() - copy_start); - result.assign(m_data.begin() + copy_start, m_data.begin() + copy_start + to_copy); - } - return result; - } - } + uint64_t file_off = get<0>(fmap) + (vaddr - seg_vaddr); + size_t avail = min(size, (size_t)(seg_vaddr + seg_size - vaddr)); + if (file_off + avail > m_data.size()) + avail = m_data.size() - file_off; + vector result(m_data.begin() + file_off, m_data.begin() + file_off + avail); + return result; } } - return result; + return {}; } vector> ELFLoader::getExecutableRanges() const diff --git a/loader/elf.hpp b/loader/elf.hpp index 792a699..5e2244c 100644 --- a/loader/elf.hpp +++ b/loader/elf.hpp @@ -39,9 +39,11 @@ class ELFLoader : public Binary addr_t m_entry; vector m_data; vector> m_exec_ranges; + vector> m_file_map; vector> m_exports; vector m_imports; map m_symbols; + string m_needed_libs; addr_t m_init_array; size_t m_init_array_size;