elf: fix readBytes to map vaddr through segment file offset

This commit is contained in:
x86byte
2026-06-29 12:25:15 +01:00
parent 5fab3a419c
commit 94cb67893c
2 changed files with 157 additions and 80 deletions
+155 -80
View File
@@ -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<SectionInfo> 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<uint64_t> 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<uint8_t> ELFLoader::readBytes(addr_t vaddr, size_t size) const
{
vector<uint8_t> 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<uint8_t> result(m_data.begin() + file_off, m_data.begin() + file_off + avail);
return result;
}
}
return result;
return {};
}
vector<pair<addr_t, addr_t>> ELFLoader::getExecutableRanges() const
+2
View File
@@ -39,9 +39,11 @@ class ELFLoader : public Binary
addr_t m_entry;
vector<uint8_t> m_data;
vector<pair<addr_t, addr_t>> m_exec_ranges;
vector<tuple<uint64_t, addr_t, uint64_t>> m_file_map;
vector<pair<addr_t, string>> m_exports;
vector<ImportEntry> m_imports;
map<addr_t, string> m_symbols;
string m_needed_libs;
addr_t m_init_array;
size_t m_init_array_size;