From fb5efbac62804ab9ce385e44914d01e2fc255659 Mon Sep 17 00:00:00 2001 From: x86byte <111459558+x86byte@users.noreply.github.com> Date: Thu, 2 Jul 2026 13:15:27 +0100 Subject: [PATCH] Fix #10 #11: 32-bit ELF loader + multi-library DT_NEEDED --- loader/elf.cpp | 252 ++++++++++++++++++++++++++++++++++++++++++++++++- loader/elf.hpp | 2 +- 2 files changed, 249 insertions(+), 5 deletions(-) diff --git a/loader/elf.cpp b/loader/elf.cpp index 611a729..f7601cf 100644 --- a/loader/elf.cpp +++ b/loader/elf.cpp @@ -171,7 +171,7 @@ bool ELFLoader::parseHeader() uint64_t val = r64(m_data, j + 8); if (tag == DT_NULL) break; - if (tag == DT_NEEDED && val && m_needed_libs.empty()) + if (tag == DT_NEEDED && val) { uint64_t strtab = 0; for (size_t k = dyn_off; k + 16 <= end; k += 16) @@ -185,8 +185,10 @@ 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++) - m_needed_libs += (char)m_data[c]; + lib += (char)m_data[c]; + if (!lib.empty()) m_needed_libs.push_back(lib); } } } @@ -324,7 +326,12 @@ bool ELFLoader::parseHeader() 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; + string lib_name; + for (size_t li = 0; li < m_needed_libs.size(); li++) + { + if (li) lib_name += ", "; + lib_name += m_needed_libs[li]; + } for (size_t j = 0; j < nrela; j++) { @@ -365,6 +372,241 @@ bool ELFLoader::parseHeader() else { m_arch = Arch::X86; + if (m_data.size() < 52) return false; + + m_entry = r32(m_data, 24); + uint32_t phoff = r32(m_data, 28); + uint32_t shoff = r32(m_data, 32); + uint16_t phnum = r16(m_data, 44); + uint16_t shnum = r16(m_data, 48); + uint16_t shstrndx = r16(m_data, 50); + + for (uint16_t i = 0; i < phnum; i++) + { + size_t off = phoff + i * 32; + if (off + 32 > m_data.size()) break; + uint32_t ptype = r32(m_data, off); + uint32_t poffset = r32(m_data, off + 4); + uint32_t pvaddr = r32(m_data, off + 8); + uint32_t pfilesz = r32(m_data, off + 16); + uint32_t pmemsz = r32(m_data, off + 20); + uint32_t pflags = r32(m_data, off + 24); + + if (ptype == PT_LOAD) + { + m_file_map.push_back({poffset, pvaddr, pmemsz}); + if (pflags & 1) + m_exec_ranges.push_back({pvaddr, pvaddr + pmemsz}); + } + + if (ptype == PT_DYNAMIC) + { + size_t dyn_off = poffset; + size_t dyn_sz = pmemsz; + size_t end = dyn_off + dyn_sz; + + for (size_t j = dyn_off; j + 8 <= end; j += 8) + { + int32_t tag = (int32_t)r32(m_data, j); + uint32_t val = r32(m_data, j + 4); + + if (tag == DT_NULL) break; + if (tag == DT_NEEDED && val) + { + uint32_t strtab = 0; + for (size_t k = dyn_off; k + 8 <= end; k += 8) + { + int32_t t2 = (int32_t)r32(m_data, k); + uint32_t v2 = r32(m_data, k + 4); + if (t2 == DT_STRTAB) { strtab = v2; break; } + } + if (strtab) + { + 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]; + if (!lib.empty()) m_needed_libs.push_back(lib); + } + } + } + if (tag == DT_INIT) m_init = val; + if (tag == DT_FINI) m_fini = val; + if (tag == DT_INIT_ARRAY) m_init_array = val; + if (tag == DT_INIT_ARRAYSZ) m_init_array_size = val; + if (tag == DT_FINI_ARRAY) m_fini_array = val; + if (tag == DT_FINI_ARRAYSZ) m_fini_array_size = val; + } + } + } + + struct SectionInfo32 { + uint32_t type; + uint32_t addr; + uint32_t offset; + uint32_t size; + uint32_t link; + uint32_t entsize; + uint32_t name_idx; + }; + vector sections(shnum); + uint32_t shstrtab_off = 0; + for (uint16_t i = 0; i < shnum; i++) + { + size_t off = shoff + i * 40; + if (off + 40 > m_data.size()) break; + sections[i].type = r32(m_data, off + 4); + sections[i].addr = r32(m_data, off + 12); + sections[i].offset = r32(m_data, off + 16); + sections[i].size = r32(m_data, off + 20); + sections[i].link = r32(m_data, off + 28); + sections[i].entsize = r32(m_data, off + 36); + sections[i].name_idx = r32(m_data, off); + if (i == shstrndx) shstrtab_off = sections[i].offset; + } + + 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) + { + uint32_t link = sections[i].link; + if (link < shnum) + strtab_offsets[i] = sections[link].offset; + } + } + + for (uint16_t i = 0; i < shnum; i++) + { + if (sections[i].type != SHT_SYMTAB && sections[i].type != SHT_DYNSYM) + continue; + + uint32_t sym_off = sections[i].offset; + uint32_t sym_sz = sections[i].size; + uint32_t entsize = sections[i].entsize ? sections[i].entsize : 16; + uint32_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 + 16 > 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); + uint32_t sym_val = r32(m_data, ent + 8); + uint32_t sym_size = r32(m_data, ent + 12); + + 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) + { + m_symbols[sym_val] = sym_name; + if (sym_bind == 1) + m_exports.push_back({sym_val, sym_name}); + } + } + } + + for (uint16_t i = 0; i < shnum; i++) + { + uint32_t sh_flags = 0; + size_t so = shoff + i * 40; + if (so + 40 > m_data.size()) continue; + sh_flags = r32(m_data, so + 8); + bool is_exec = (sh_flags & 0x4) != 0; + bool is_alloc = (sh_flags & 0x2) != 0; + if (is_alloc && !is_exec && sections[i].addr && sections[i].size) + m_data_ranges.push_back({sections[i].addr, sections[i].addr + sections[i].size}); + } + + 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; + + uint32_t rela_off = sections[i].offset; + uint32_t rela_sz = sections[i].size; + size_t nrela = rela_sz / 12; + if (nrela == 0) continue; + + uint32_t symtab_link = sections[i].link; + if (symtab_link >= shnum) continue; + + uint32_t sym_off = sections[symtab_link].offset; + uint32_t sym_sz = sections[symtab_link].size; + uint32_t str_off2 = 0; + uint32_t str_link = sections[symtab_link].link; + if (str_link < shnum) str_off2 = sections[str_link].offset; + uint32_t sym_entsize = sections[symtab_link].entsize ? sections[symtab_link].entsize : 16; + + string lib_name; + for (size_t li = 0; li < m_needed_libs.size(); li++) + { + if (li) lib_name += ", "; + lib_name += m_needed_libs[li]; + } + + for (size_t j = 0; j < nrela; j++) + { + size_t ent = rela_off + j * 12; + if (ent + 12 > m_data.size()) break; + uint32_t r_offset = r32(m_data, ent); + uint32_t r_info = r32(m_data, ent + 4); + uint32_t sym_idx = r_info >> 8; + + if (!sym_idx) continue; + + size_t sym_ent = sym_off + sym_idx * sym_entsize; + if (sym_ent + 16 > 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); + } + } } return true; @@ -395,8 +637,10 @@ vector ELFLoader::readBytes(addr_t vaddr, size_t size) const { 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()) + if (file_off >= m_data.size()) avail = 0; + else 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; } diff --git a/loader/elf.hpp b/loader/elf.hpp index e273d4c..bc2678d 100644 --- a/loader/elf.hpp +++ b/loader/elf.hpp @@ -50,7 +50,7 @@ class ELFLoader : public Binary vector> m_exports; vector m_imports; map m_symbols; - string m_needed_libs; + vector m_needed_libs; addr_t m_init_array; size_t m_init_array_size;