#include #ifndef _MSC_VER #include #endif #include #include #include "elfview.h" #define STRING_READ_CHUNK_SIZE 32 using namespace BinaryNinja; using namespace std; static ElfViewType* g_elfViewType = nullptr; void BinaryNinja::InitElfViewType() { static ElfViewType type; BinaryViewType::Register(&type); g_elfViewType = &type; Ref settings = Settings::Instance(); settings->RegisterSetting("files.elf.maxSectionHeaderCount", R"({ "title" : "Maximum ELF Section Header Count", "type" : "number", "default" : 100, "minValue" : 0, "maxValue" : 65536, "description" : "Maximum number of entries to include in section header array", "ignore" : ["SettingsProjectScope"] })"); settings->RegisterSetting("files.elf.detectARMBE8Binary", R"({ "title" : "Enable ARM BE8 binary detection", "type" : "boolean", "default" : true, "description" : "Enable ARM BE8 binary detection for mixed little/big endianness for code/data", "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] })"); settings->RegisterSetting("files.elf.overrideX86Endianness", R"~({ "title" : "Override x86 ELF endianness", "type" : "boolean", "default" : true, "description" : "Automatically override endianness to little-endian for x86/x86_64 ELF files (useful for obfuscated binaries)", "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] })~"); } ElfView::ElfView(BinaryView* data, bool parseOnly): BinaryView("ELF", data->GetFile(), data), m_parseOnly(parseOnly) { CreateLogger("BinaryView"); m_logger = CreateLogger("BinaryView.ElfView"); Elf64Header header; string errorMsg; BNEndianness endian; if (!ParseHeaders(data, m_ident, m_commonHeader, header, &m_arch, &m_plat, errorMsg, endian)) throw ElfFormatException(errorMsg); m_elf32 = m_ident.fileClass == 1; m_addressSize = (m_ident.fileClass == 1 || (m_plat && m_plat->GetName() == "linux-x32") || (m_plat && m_plat->GetName() == "linux-ilp32")) ? 4 : 8; m_endian = endian; m_relocatable = m_commonHeader.type == ET_DYN || m_commonHeader.type == ET_REL; m_objectFile = m_commonHeader.type == ET_REL; m_backedByDatabase = data->GetFile()->IsBackedByDatabase("ELF"); memset(&m_symbolTableSection, 0, sizeof(m_symbolTableSection)); memset(&m_dynamicSymbolTableSection, 0, sizeof(m_dynamicSymbolTableSection)); memset(&m_dynamicStringTable, 0, sizeof(m_dynamicStringTable)); memset(&m_dynamicTable, 0, sizeof(m_dynamicTable)); memset(&m_relocSection, 0, sizeof(m_relocSection)); memset(&m_relocaSection, 0, sizeof(m_relocaSection)); memset(&m_tlsSegment, 0, sizeof(m_tlsSegment)); memset(&m_auxSymbolTable, 0, sizeof(m_auxSymbolTable)); memset(&m_sectionStringTable, 0, sizeof(m_sectionStringTable)); memset(&m_sectionOpd, 0, sizeof(m_sectionOpd)); if (m_elf32 && (header.sectionHeaderSize != sizeof(Elf32SectionHeader))) { m_logger->LogWarn( "The section header size reported by e_shentsize (0x%lx) is different from the size of Elf32_Shdr (0x%lx). " "The parsing proceeds with the size of Elf32_Shdr.", header.sectionHeaderSize, sizeof(Elf32SectionHeader)); header.sectionHeaderSize = sizeof(Elf32SectionHeader); } else if (!m_elf32 && (header.sectionHeaderSize != sizeof(Elf64SectionHeader))) { m_logger->LogWarn( "The section header size reported by e_shentsize (0x%lx) is different from the size of Elf64_Shdr (0x%lx). " "The parsing proceeds with the size of Elf64_Shdr.", header.sectionHeaderSize, sizeof(Elf64SectionHeader)); header.sectionHeaderSize = sizeof(Elf64SectionHeader); } if (m_elf32 && (header.programHeaderSize != sizeof(Elf32ProgramHeader))) { m_logger->LogWarn( "The program header size reported by e_phentsize (0x%lx) is different from the size of Elf32_Phdr (0x%lx). " "The parsing proceeds with the size of Elf32_Phdr.", header.programHeaderSize, sizeof(Elf32ProgramHeader)); header.programHeaderSize = sizeof(Elf32ProgramHeader); } else if (!m_elf32 && (header.programHeaderSize != sizeof(Elf64ProgramHeader))) { m_logger->LogWarn( "The program header size reported by e_phentsize (0x%lx) is different from the size of Elf64_Phdr (0x%lx). " "The parsing proceeds with the size of Elf64_Phdr.", header.programHeaderSize, sizeof(Elf64ProgramHeader)); header.programHeaderSize = sizeof(Elf64ProgramHeader); } m_entryPoint = header.entry; m_sectionHeaderOffset = header.sectionHeaderOffset; m_sectionHeaderCount = header.sectionHeaderCount; m_programHeaderOffset = header.programHeaderOffset; m_programHeaderCount = header.programHeaderCount; m_headerFlags = header.flags; m_fileSize = data->GetLength(); m_logger->LogDebug( "ELF Header\n" "\t%d bits\n" "\theader.entry %016x\n" "\theader.programHeaderOffset %016x\n" "\theader.sectionHeaderOffset %016x\n" "\theader.flags %016x\n" "\theader.headerSize %016x\n" "\theader.programHeaderSize %016x\n" "\theader.programHeaderCount %016x\n" "\theader.sectionHeaderSize %016x\n" "\theader.sectionHeaderCount %016x\n" "\theader.stringTable %016x\n", m_addressSize * 8, header.entry, header.programHeaderOffset, header.sectionHeaderOffset, header.flags, header.headerSize, header.programHeaderSize, header.programHeaderCount, header.sectionHeaderSize, header.sectionHeaderCount, header.stringTable); BinaryReader reader(data); reader.SetEndianness(m_endian); // Parse program headers reader.Seek(header.programHeaderOffset); for (size_t i = 0; i < header.programHeaderCount; i++) { Elf64ProgramHeader progHeader; if (m_elf32) // 32-bit ELF { progHeader.type = reader.Read32(); progHeader.offset = reader.Read32(); progHeader.virtualAddress = reader.Read32(); progHeader.physicalAddress = reader.Read32(); progHeader.fileSize = reader.Read32(); progHeader.memorySize = reader.Read32(); progHeader.flags = reader.Read32(); progHeader.align = reader.Read32(); } else // 64-bit ELF { progHeader.type = reader.Read32(); progHeader.flags = reader.Read32(); progHeader.offset = reader.Read64(); progHeader.virtualAddress = reader.Read64(); progHeader.physicalAddress = reader.Read64(); progHeader.fileSize = reader.Read64(); progHeader.memorySize = reader.Read64(); progHeader.align = reader.Read64(); } m_logger->LogDebug( "\tSegment: %d\n" "\t\tprogHeader.type %08x\n" "\t\tprogHeader.offset %08x\n" "\t\tprogHeader.virtualAddress %016x\n" "\t\tprogHeader.physicalAddress %016x\n" "\t\tprogHeader.fileSize %016x\n" "\t\tprogHeader.memorySize %016x\n" "\t\tprogHeader.flags %016x\n" "\t\tprogHeader.align %016x\n", i, progHeader.type, progHeader.offset, progHeader.virtualAddress, progHeader.physicalAddress, progHeader.fileSize, progHeader.memorySize, progHeader.flags, progHeader.align); if (!memcmp(m_ident.signature, "\x7f" "CGC", 4)) { // CGC uses physical address for loading uint64_t temp = progHeader.virtualAddress; progHeader.virtualAddress = progHeader.physicalAddress; progHeader.physicalAddress = temp; } m_programHeaders.push_back(progHeader); if (progHeader.type == ELF_PT_DYNAMIC) m_dynamicTable = progHeader; if (progHeader.type == ELF_PT_TLS) m_tlsSegment = progHeader; } // Parse section headers try { reader.Seek(header.sectionHeaderOffset); m_logger->LogDebug("Section List"); for (size_t i = 0; i < header.sectionHeaderCount; i++) { Elf64SectionHeader section; reader.Seek(header.sectionHeaderOffset + (i * header.sectionHeaderSize)); if (m_elf32) // 32-bit ELF { section.name = reader.Read32(); section.type = reader.Read32(); section.flags = reader.Read32(); section.address = reader.Read32(); section.offset = reader.Read32(); section.size = reader.Read32(); section.link = reader.Read32(); section.info = reader.Read32(); section.align = reader.Read32(); section.entrySize = reader.Read32(); } else // 64-bit ELF { section.name = reader.Read32(); section.type = reader.Read32(); section.flags = reader.Read64(); section.address = reader.Read64(); section.offset = reader.Read64(); section.size = reader.Read64(); section.link = reader.Read32(); section.info = reader.Read32(); section.align = reader.Read64(); section.entrySize = reader.Read64(); } m_elfSections.push_back(section); if (section.size > m_fileSize) { m_logger->LogWarn("Section %lu has a size (0x%lx) larger than file size (0x%lx), skipping creation", i, section.size, m_fileSize); continue; } if (section.type == ELF_SHT_SYMTAB) m_symbolTableSection = section; else if (section.type == ELF_SHT_DYNSYM) m_dynamicSymbolTableSection = section; else if (section.type == ELF_SHT_STRTAB) { ApplyTypesToParentStringTable(section); if (i == header.stringTable) { m_sectionStringTable = section; } continue; } if (section.flags & ELF_SHF_STRINGS) ApplyTypesToParentStringTable(section, false); } } catch (ReadException&) { // Section headers are not required for a valid ELF, skip errors m_logger->LogError("ELF section headers invalid"); } for (size_t i = 0; i < m_elfSections.size(); i++) { const string scnNameString = ReadStringTable(reader, m_sectionStringTable, m_elfSections[i].name); m_logger->LogDebug("\tSection: %d\n" "\t\tsection.name %08x (%s)\n" "\t\tsection.type %08x\n" "\t\tsection.flags %016x\n" "\t\tsection.address %016x\n" "\t\tsection.offset %016x\n" "\t\tsection.size %016x\n" "\t\tsection.link %08x\n" "\t\tsection.info %016x\n" "\t\tsection.align %016x\n" "\t\tsection.entrySize %016x", i, m_elfSections[i].name, scnNameString.c_str(), m_elfSections[i].type, m_elfSections[i].flags, m_elfSections[i].address, m_elfSections[i].offset, m_elfSections[i].size, m_elfSections[i].link, m_elfSections[i].info, m_elfSections[i].align, m_elfSections[i].entrySize ); if (!m_elf32 && m_commonHeader.arch == EM_PPC64 && scnNameString == ".opd") m_sectionOpd = m_elfSections[i]; } /* TODO: PPC64 specific entrypoint handling to be moved to architecture extension for ELF */ if (m_commonHeader.arch == EM_PPC64) { uint64_t entry; if (DerefPpc64Descriptor(reader, m_entryPoint, entry)) { m_logger->LogDebug("PPC64 dereference m_entryPoint=%016x to %016x\n", m_entryPoint, entry); m_entryPoint = entry; } else { m_logger->LogDebug("PPC64 unable to dereference m_entryPoint=%016x\n", m_entryPoint); } } } ElfView::~ElfView() { for (auto& i : m_relocationInfo) { auto cur = i.next; while (cur) { auto next = cur->next; delete cur; cur = next; } } } static BNSymbolBinding TranslateELFBindingType(uint8_t type) { switch (type) { case ELF_STB_LOCAL: return LocalBinding; case ELF_STB_GLOBAL: return GlobalBinding; case ELF_STB_WEAK: return WeakBinding; default: return NoBinding; } } bool ElfView::ParseSymbolTableEntry(BinaryReader& reader, ElfSymbolTableEntry& entry, uint64_t sym, const Elf64SectionHeader& symbolTable, const Elf64SectionHeader& stringTable, bool dynamic) { try { entry.dynamic = dynamic; if (m_elf32) { reader.Seek(symbolTable.offset + (sym * 16)); entry.nameOffset = reader.Read32(); entry.value = reader.Read32(); entry.size = reader.Read32(); uint8_t info = reader.Read8(); entry.type = ELF_ST_TYPE(info); entry.binding = TranslateELFBindingType(ELF_ST_BIND(info)); entry.other = reader.Read8(); entry.section = reader.Read16(); } else { reader.Seek(symbolTable.offset + (sym * 24)); entry.nameOffset = reader.Read32(); uint8_t info = reader.Read8(); entry.type = ELF_ST_TYPE(info); entry.binding = TranslateELFBindingType(ELF_ST_BIND(info)); entry.other = reader.Read8(); entry.section = reader.Read16(); entry.value = reader.Read64(); entry.size = reader.Read64(); } if (entry.type == ELF_STT_SECTION) { if (entry.section < m_elfSections.size()) { entry.name = ReadStringTable(reader, m_sectionStringTable, m_elfSections[entry.section].name); } } else { entry.name = ReadStringTable(reader, stringTable, entry.nameOffset); } } catch (ReadException&) { return false; } m_logger->LogDebug( "Symbol: %d - symbolSection.offset: %lx - stringSection.offset: %lx\n" "\tnameOffset = %#08lx\n" "\ttype = %#02x\n" "\tbinding = %#02x\n" "\tother = %#02x\n" "\tsection = %#04x\n" "\tvalue = %#012lx\n" "\tsize = %#012lx\n" "\tname = %#s", sym, symbolTable.offset, stringTable.offset, entry.nameOffset, entry.type, entry.binding, entry.other, entry.section, entry.value, entry.size, entry.name.c_str()); return true; } void ElfView::GetRelocEntries(BinaryReader& reader, const vector& sections, bool implicit, vector& result) { size_t relocSize = m_elf32 ? 8 : 16; if (!implicit) relocSize += m_elf32 ? 4 : 8; for (auto& section : sections) { for (uint64_t j = 0; j < section.size / relocSize; j++) { reader.Seek(section.offset + (j * relocSize)); if (!m_elf32 && (m_commonHeader.arch == EM_MIPS)) { // MIPS64 relocations apparently use dedicated r_sym/r_type fields. // See page 40, table 29 of the 64-bit ELF Object File Specification // published by MIPS/SGCS (document no. 007-4658-001). uint64_t ofs = reader.Read64(); uint64_t sym = reader.Read32(); uint32_t ssym = reader.Read8(); uint32_t type3 = reader.Read8(); uint32_t type2 = reader.Read8(); uint32_t type = reader.Read8(); uint64_t addend = 0; if (!implicit) addend = reader.Read64(); uint64_t relocType = type | (type2 << 8) | (type3 << 16); (void)ssym; result.push_back(ELFRelocEntry(ofs, sym, relocType, addend, section.info, implicit)); continue; } uint64_t ofs = m_elf32 ? reader.Read32() : reader.Read64(); uint64_t info = m_elf32 ? reader.Read32() : reader.Read64(); uint64_t addend = 0; if (!implicit) addend = m_elf32 ? reader.Read32() : reader.Read64(); uint64_t sym = info >> (m_elf32 ? 8 : 32); uint64_t relocType = info & (m_elf32 ? 0xff : 0xffffffff); result.push_back(ELFRelocEntry(ofs, sym, relocType, addend, section.info, implicit)); } } } static bool In(const string& str, const vector& list) { for (auto& a : list) if (a == str) return true; return false; } bool ElfView::Init() { std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now(); // Add segments for the program headers BinaryReader reader(GetParentView()); BinaryReader virtualReader(this); uint64_t initialImageBase = 0; bool initialImageBaseSet = false; for (const auto& i : m_programHeaders) { // Skip segments that are not loadable or have no memory size if ((i.type != ELF_PT_LOAD) || (i.memorySize == 0)) continue; if (!initialImageBaseSet || (i.virtualAddress < initialImageBase)) { initialImageBase = i.virtualAddress; initialImageBaseSet = true; } } SetOriginalImageBase(initialImageBase); uint64_t preferredImageBase = initialImageBase; Ref viewSettings = Settings::Instance(); m_extractMangledTypes = viewSettings->Get("analysis.extractTypesFromMangledNames", this); m_simplifyTemplates = viewSettings->Get("analysis.types.templateSimplifier", this); bool platformSetByUser = false; Ref settings = GetLoadSettings(GetTypeName()); if (settings) { if (settings->Contains("loader.imageBase")) preferredImageBase = settings->Get("loader.imageBase", this); if (settings->Contains("loader.platform")) { BNSettingsScope scope = SettingsAutoScope; Ref platformOverride = Platform::GetByName(settings->Get("loader.platform", this, &scope)); if (platformOverride) { m_plat = platformOverride; m_arch = m_plat->GetArchitecture(); platformSetByUser = (scope == SettingsResourceScope); } } } int64_t imageBaseAdjustment = 0; if (!initialImageBase) imageBaseAdjustment = preferredImageBase; else if (initialImageBase <= preferredImageBase) imageBaseAdjustment = preferredImageBase - initialImageBase; else imageBaseAdjustment = -(int64_t)(initialImageBase - preferredImageBase); m_entryPoint = m_entryPoint + imageBaseAdjustment; BeginBulkAddSegments(); for (auto& i : m_programHeaders) { uint64_t adjustedVirtualAddr = i.virtualAddress + imageBaseAdjustment; if (i.type == ELF_PT_LOAD) // || i.type == ELF_PT_GNU_RELRO) { uint32_t flags = 0; if (i.flags & 1) flags |= SegmentExecutable; if (i.flags & 2) flags |= SegmentWritable; if (i.flags & 4) flags |= SegmentReadable; AddAutoSegment(adjustedVirtualAddr, i.memorySize, i.offset, i.fileSize, flags); } // Create sections for the program headers with the standard section names. This will ensure that // the standard name for sections such as .dynamic will always refer to what the loader actually uses. if (i.type == ELF_PT_DYNAMIC) { uint64_t entrySize = m_elf32 ? 8 : 16; bool foundMatch = false; for (size_t j = 1; j < m_elfSections.size(); j++) { uint64_t adjustedSectionAddr = m_elfSections[j].address + imageBaseAdjustment; if (m_elfSections[j].type != ELF_SHT_DYNAMIC) continue; if (adjustedSectionAddr != adjustedVirtualAddr) continue; if (m_elfSections[j].size != i.memorySize) continue; if (m_elfSections[j].entrySize != entrySize) continue; if (ReadStringTable(reader, m_sectionStringTable, m_elfSections[j].name) != ".dynamic") continue; foundMatch = true; break; } if (!foundMatch) AddAutoSection(".dynamic", adjustedVirtualAddr, i.memorySize, ReadOnlyDataSectionSemantics, "DYNAMIC", i.align, entrySize); } else if (i.type == ELF_PT_INTERP) { bool foundMatch = false; for (size_t j = 1; j < m_elfSections.size(); j++) { uint64_t adjustedSectionAddr = m_elfSections[j].address + imageBaseAdjustment; if (m_elfSections[j].type != ELF_SHT_PROGBITS) continue; if (adjustedSectionAddr != adjustedVirtualAddr) continue; if (m_elfSections[j].size != i.memorySize) continue; if (ReadStringTable(reader, m_sectionStringTable, m_elfSections[j].name) != ".interp") continue; foundMatch = true; break; } if (!foundMatch) AddAutoSection(".interp", adjustedVirtualAddr, i.memorySize, ReadOnlyDataSectionSemantics, "PROGBITS", i.align); DefineDataVariable(adjustedVirtualAddr, Type::ArrayType(Type::IntegerType(1, true), i.fileSize)); DefineAutoSymbol(new Symbol(DataSymbol, "__elf_interp", adjustedVirtualAddr, LocalBinding)); } } EndBulkAddSegments(); // Gather names for the sections vector sectionNames {""}; for (size_t i = 1; i < m_elfSections.size(); i++) sectionNames.push_back(ReadStringTable(reader, m_sectionStringTable, m_elfSections[i].name)); sectionNames = GetUniqueSectionNames(sectionNames); // Add sections to the view vector dynRelocSections, dynRelocASections; vector relocSections, relocASections; Elf64SectionHeader symbolTableSection; BeginBulkAddSegments(); uint64_t segmentStart = 0; for (size_t i = 1; i < m_elfSections.size(); i++) { string type; string linkedSection, infoSection; switch (m_elfSections[i].type) { case ELF_SHT_PROGBITS: type = "PROGBITS"; break; case ELF_SHT_SYMTAB: type = "SYMTAB"; symbolTableSection = m_elfSections[i]; break; case ELF_SHT_STRTAB: type = "STRTAB"; break; case ELF_SHT_RELA: type = "RELA"; relocASections.push_back(m_elfSections[i]); break; case ELF_SHT_REL: type = "REL"; relocSections.push_back(m_elfSections[i]); break; case ELF_SHT_HASH: type = "HASH"; break; case ELF_SHT_DYNAMIC: type = "DYNAMIC"; break; case ELF_SHT_NOTE: type = "NOTE"; break; case ELF_SHT_NOBITS: type = "NOBITS"; break; case ELF_SHT_SHLIB: type = "SHLIB"; break; case ELF_SHT_DYNSYM: type = "DYNSYM"; break; default: break; } // Add sections that aren't in the virtual address space only to the raw parent view if (!(m_elfSections[i].flags & ELF_SHF_ALLOC) || m_elfSections[i].type == ELF_SHT_NOTE) { if (m_elfSections[i].size != 0 && m_elfSections[i].type != ELF_SHT_NOBITS) GetParentView()->AddAutoSection(sectionNames[i], m_elfSections[i].offset, m_elfSections[i].size, DefaultSectionSemantics, type, m_elfSections[i].align, m_elfSections[i].entrySize, linkedSection, infoSection, m_elfSections[i].info); continue; } if (m_elfSections[i].type == ELF_SHT_STRTAB) ApplyTypesToStringTable(m_elfSections[i], imageBaseAdjustment); else if (m_elfSections[i].flags & ELF_SHF_STRINGS) ApplyTypesToStringTable(m_elfSections[i], imageBaseAdjustment, false); if (m_elfSections[i].link < m_elfSections.size()) linkedSection = sectionNames[m_elfSections[i].link]; BNSectionSemantics semantics = DefaultSectionSemantics; vector readOnlyCodeSectionNames = {".text", ".init", ".fini"}; vector readWriteDataSectionNames = {".data", ".bss"}; vector readOnlyDataSectionNames = {".rodata", ".dynamic", ".dynsym", ".dynstr", ".ehframe", ".ctors", ".dtors", ".got", ".got2", ".data.rel.ro", ".gnu.hash"}; if (m_arch && m_arch->GetName() == "hexagon") { readOnlyDataSectionNames.emplace_back(".got.plt"); } if ((m_elfSections[i].flags & ELF_SHF_EXECINSTR) || In(sectionNames[i], readOnlyCodeSectionNames)) semantics = ReadOnlyCodeSectionSemantics; else if (!(m_elfSections[i].flags & ELF_SHF_WRITE) || In(sectionNames[i], readOnlyDataSectionNames)) semantics = ReadOnlyDataSectionSemantics; else if ((m_elfSections[i].flags & ELF_SHF_WRITE) || In(sectionNames[i], readWriteDataSectionNames)) semantics = ReadWriteDataSectionSemantics; if (m_elfSections[i].size != 0) { if (m_programHeaders.size() == 0) { // We have an object file so we'll just create segments for the sections uint32_t flags = 0; if (semantics == ReadOnlyCodeSectionSemantics) flags = SegmentReadable | SegmentExecutable; else if (semantics == ReadWriteDataSectionSemantics) flags = SegmentReadable | SegmentWritable; else if (semantics == ReadOnlyDataSectionSemantics) flags = SegmentReadable; if ((m_commonHeader.type == ET_DYN) && (!m_parseOnly)) { // We have a shared object file without program headers so we'll create segments for the sections // based on the section address. size_t size = m_elfSections[i].type == ELF_SHT_NOBITS ? 0 : m_elfSections[i].size; uint64_t adjustedSectionAddr = m_elfSections[i].address + imageBaseAdjustment; AddAutoSegment(adjustedSectionAddr, m_elfSections[i].size, m_elfSections[i].offset, size, flags); } else { m_elfSections[i].address = segmentStart; size_t size = m_elfSections[i].type == ELF_SHT_NOBITS ? 0 : m_elfSections[i].size; uint64_t adjustedSectionAddr = m_elfSections[i].address + imageBaseAdjustment; AddAutoSegment(adjustedSectionAddr, m_elfSections[i].size, m_elfSections[i].offset, size, flags); segmentStart += ((m_elfSections[i].size + 15) & ~15); } } else if ((m_elfSections[i].address + m_elfSections[i].size + imageBaseAdjustment) > GetEnd() || ((m_elfSections[i].address + imageBaseAdjustment) < GetStart())) { LogWarn("Section %s is outside of the address space of the file and will not be added", sectionNames[i].c_str()); continue; } uint64_t adjustedVirtualAddr = m_elfSections[i].address + imageBaseAdjustment; AddAutoSection(sectionNames[i], adjustedVirtualAddr, m_elfSections[i].size, semantics, type, m_elfSections[i].align, m_elfSections[i].entrySize, linkedSection, infoSection, m_elfSections[i].info); if (m_elfSections[i].type != ELF_SHT_NOBITS) GetParentView()->AddAutoSection(sectionNames[i], m_elfSections[i].offset, m_elfSections[i].size, DefaultSectionSemantics, type, m_elfSections[i].align, m_elfSections[i].entrySize, linkedSection, infoSection, m_elfSections[i].info); } } EndBulkAddSegments(); // Apply architecture and platform if (!m_arch) { switch (m_commonHeader.arch) { case 3: m_logger->LogError("Support for ELF architecture 'x86' is not present"); break; case 8: #ifndef DEMO_EDITION m_logger->LogError("Support for ELF architecture 'mips' is not present"); #else m_logger->LogError("Binary Ninja free does not support ELF architecture 'mips'. " "Purchase Binary Ninja to unlock all features."); #endif break; case 20: #ifndef DEMO_EDITION m_logger->LogError("Support for ELF architecture 'ppc' is not present"); #else m_logger->LogError("Binary Ninja free does not support ELF architecture 'ppc'. " "Purchase Binary Ninja to unlock all features."); #endif break; case 21: #ifndef DEMO_EDITION m_logger->LogError("Support for ELF architecture 'ppc64' is not present"); #else m_logger->LogError("Binary Ninja free does not support ELF architecture 'ppc64'. " "Purchase Binary Ninja to unlock all features."); #endif break; case 40: m_logger->LogError("Support for ELF architecture 'armv7' is not present"); break; case 62: m_logger->LogError("Support for ELF architecture 'x86_64' is not present"); break; case 183: #ifndef DEMO_EDITION m_logger->LogError("Support for ELF architecture 'arm64' is not present"); #else m_logger->LogError("Binary Ninja free does not support ELF architecture 'arm64'. " "Purchase Binary Ninja to unlock all features."); #endif break; default: m_logger->LogError("ELF architecture %d is not supported", m_commonHeader.arch); break; } if (!m_parseOnly) m_logger->LogWarn("Unable to determine architecture. Please open the file with options and select a valid architecture."); return false; } // Add the entry point as a function if the architecture is supported uint64_t entryPointAddress = m_entryPoint; Ref entryPointArch = m_arch->GetAssociatedArchitectureByAddress(entryPointAddress); SetDefaultArchitecture(entryPointArch); GetParentView()->SetDefaultArchitecture(entryPointArch); Ref platform = m_plat ? m_plat : g_elfViewType->GetPlatform(m_ident.os, m_arch); if (platform && (entryPointArch != m_arch) && !platformSetByUser) platform = platform->GetRelatedPlatform(entryPointArch); if (!platform) platform = entryPointArch->GetStandalonePlatform(); SetDefaultPlatform(platform); GetParentView()->SetDefaultPlatform(platform); // Finished for parse only mode if (m_parseOnly) { m_stringTableCache.clear(); return true; } // Set reader endianness reader.SetEndianness(m_endian); virtualReader.SetEndianness(m_endian); // FIXME: MIPS specific GOT entries should be done in the MIPS plugin, once there is a way to have // ELF parsing extensions in an architecture plugin uint64_t gotStart = 0; uint64_t localMipsSyms = 0; uint64_t firstMipsSym = 0; uint64_t baseAddress = GetStart(); vector neededLibraries; bool mipsSymValid = false; // FIXME: ARM specific GOT entries should be done in the MIPS plugin, as above bool isArmV7 = m_arch->GetName() == "armv7"; vector tlsModuleStarts; vector tlsOffsets; // Parse dynamic table if (auto dynSeg = GetSegmentAt(m_dynamicTable.virtualAddress + imageBaseAdjustment); dynSeg && m_dynamicTable.virtualAddress) { try { uint64_t adjustedVirtualAddr = m_dynamicTable.virtualAddress + imageBaseAdjustment; reader.Seek(adjustedVirtualAddr - dynSeg->GetStart() + dynSeg->GetDataOffset()); Elf64SectionHeader plt; memset(&plt, 0, sizeof(plt)); uint64_t pltType = ELF_DT_RELA; bool end = false; uint64_t entrySize = m_elf32 ? 8 : 16; size_t i = 0; while (!end) { uint64_t tag, value; if (i >= m_dynamicTable.fileSize) { // Prevent reading past end of dynamic table in file end = true; break; } if (m_elf32) // 32-bit ELF { tag = reader.Read32(); value = reader.Read32(); i += 8; } else // 64-bit ELF { tag = reader.Read64(); value = reader.Read64(); i += 16; } switch (tag) { case ELF_DT_NULL: end = true; m_numDynamicTableEntries = i ? i / entrySize : 0; break; case ELF_DT_NEEDED: neededLibraries.push_back(value); break; case ELF_DT_PLTREL: pltType = value; break; case ELF_DT_JMPREL: plt.offset = value + imageBaseAdjustment; break; case ELF_DT_PLTRELSZ: plt.size = value; break; case ELF_DT_STRTAB: m_dynamicStringTable.offset = value + imageBaseAdjustment; break; case ELF_DT_SYMTAB: m_auxSymbolTable.offset = value + imageBaseAdjustment; break; case ELF_DT_SYMENT: m_auxSymbolTableEntrySize = value; break; case ELF_DT_INIT: case ELF_DT_FINI: { uint64_t target = value + imageBaseAdjustment; string autoName = (tag == ELF_DT_INIT) ? "_init" : "_fini"; DefineAutoSymbol(new Symbol(FunctionSymbol, autoName, target, NoBinding)); Ref targetPlatform = platform->GetAssociatedPlatformByAddress(target); AddFunctionForAnalysis(targetPlatform, target); break; } case ELF_DT_HASH: m_hashHeader = value + imageBaseAdjustment; break; case ELF_DT_GNU_HASH: m_gnuHashHeader = value + imageBaseAdjustment; break; case ELF_DT_RELA: m_relocaSection.offset = value + imageBaseAdjustment; break; case ELF_DT_RELASZ: m_relocaSection.size = value; break; case ELF_DT_RELAENT: m_relocaSection.entrySize = value; break; case ELF_DT_STRSZ: m_dynamicStringTable.size = value; break; case ELF_DT_REL: m_relocSection.offset = value + imageBaseAdjustment; break; case ELF_DT_RELSZ: m_relocSection.size = value; break; case ELF_DT_RELENT: m_relocSection.entrySize = value; break; case ELF_DT_PLTGOT: gotStart = value + imageBaseAdjustment; break; case ELF_DT_MIPS_SYMTABNO: m_auxSymbolTable.size = m_elf32 ? value * 16 : value * 24; break; case ELF_DT_MIPS_LOCAL_GOTNO: localMipsSyms = value; break; case ELF_DT_MIPS_GOTSYM: firstMipsSym = value; mipsSymValid = true; break; case ELF_DT_MIPS_BASE_ADDRESS: baseAddress = value + imageBaseAdjustment; break; default: break; } } vector> libraries; vector> libraryFound; for (auto& libNameOffset : neededLibraries) { const string libName = ReadStringTable(virtualReader, m_dynamicStringTable, libNameOffset); if (!GetExternalLibrary(libName)) { AddExternalLibrary(libName, {}, true); } libraries.push_back(new Metadata(string(libName))); Ref typeLib = GetTypeLibrary(libName); if (!typeLib) { vector> typeLibs = platform->GetTypeLibrariesByName(libName); if (typeLibs.size()) { typeLib = typeLibs[0]; AddTypeLibrary(typeLib); m_logger->LogDebug("elf: adding type library for '%s': %s (%s)", libName.c_str(), typeLib->GetName().c_str(), typeLib->GetGuid().c_str()); } } if (typeLib) libraryFound.push_back(new Metadata(typeLib->GetName())); else libraryFound.push_back(new Metadata(string(""))); } StoreMetadata("Libraries", new Metadata(libraries), true); StoreMetadata("LibraryFound", new Metadata(libraryFound), true); if (m_relocaSection.size > 0) { bool alreadyExists = false; for (auto& relSec : relocASections) if (relSec.offset == m_relocaSection.offset) alreadyExists = true; if (!alreadyExists) { dynRelocASections.push_back(m_relocaSection); AddAutoSection( ".dynamic_rela", m_relocaSection.offset, m_relocaSection.size, ReadOnlyDataSectionSemantics); } } if (plt.size > 0) { if (pltType == ELF_DT_REL) { bool alreadyExists = false; for (auto& relSec : relocSections) if ((relSec.address + imageBaseAdjustment) == plt.offset) alreadyExists = true; if (!alreadyExists) { dynRelocSections.push_back(plt); AddAutoSection(".dynamic_jmprel", plt.offset, plt.size, ReadOnlyDataSectionSemantics); } } else { bool alreadyExists = false; for (auto& relSec : relocASections) if ((relSec.address + imageBaseAdjustment) == plt.offset) alreadyExists = true; if (!alreadyExists) { dynRelocASections.push_back(plt); AddAutoSection(".dynamic_jmprel", plt.offset, plt.size, ReadOnlyDataSectionSemantics); } } } if (m_relocSection.size > 0) { bool alreadyExists = false; for (auto& relSec : relocSections) if ((relSec.address + imageBaseAdjustment) == m_relocSection.offset) alreadyExists = true; if (!alreadyExists) { dynRelocSections.push_back(m_relocSection); AddAutoSection( ".dynamic_rel", m_relocSection.offset, m_relocSection.size, ReadOnlyDataSectionSemantics); } } } catch (ReadException&) { m_logger->LogError("ELF dynamic table invalid"); } } // Parse symbol table vector symbolTable, dynamicSymbolTable; try { if ((m_symbolTableSection.size > 0) && (m_symbolTableSection.link < m_elfSections.size())) { symbolTable = ParseSymbolTable(reader, m_symbolTableSection, m_elfSections[m_symbolTableSection.link], false); } if ((m_dynamicSymbolTableSection.size > 0) && (m_dynamicSymbolTableSection.link < m_elfSections.size())) { dynamicSymbolTable = ParseSymbolTable(reader, m_dynamicSymbolTableSection, m_elfSections[m_dynamicSymbolTableSection.link], true); } } catch (ReadException&) { // Symbol table is not critical to execution, skip errors m_logger->LogError("ELF symbol table invalid"); } vector relocs; try { GetRelocEntries(virtualReader, dynRelocSections, true, relocs); GetRelocEntries(virtualReader, dynRelocASections, false, relocs); GetRelocEntries(reader, relocSections, true, relocs); GetRelocEntries(reader, relocASections, false, relocs); for (auto& reloc : relocs) reloc.offset += imageBaseAdjustment; } catch (ReadException&) { // Skip errors in relocation tables m_logger->LogError("ELF relocation table invalid"); } BulkSymbolModification bulkSymbolModification(this); vector auxSymbolTable; try { if (!m_auxSymbolTableEntrySize) m_auxSymbolTableEntrySize = m_elf32 ? 16 : 24; // Parse and create types for ELF hash table if (m_hashHeader) { virtualReader.Seek(m_hashHeader); uint32_t nbucket = virtualReader.Read32(); uint32_t nchain = virtualReader.Read32(); m_auxSymbolTable.size = m_auxSymbolTableEntrySize * nchain; auxSymbolTable = ParseSymbolTable(virtualReader, m_auxSymbolTable, m_dynamicStringTable, true); StructureBuilder hashTableBuilder; hashTableBuilder.AddMember(Type::IntegerType(4, false), "nbucket"); hashTableBuilder.AddMember(Type::IntegerType(4, false), "nchain"); hashTableBuilder.AddMember(Type::ArrayType(Type::IntegerType(4, false), nbucket), "buckets"); hashTableBuilder.AddMember(Type::ArrayType(Type::IntegerType(4, false), nchain), "chains"); Ref hashTableStruct = hashTableBuilder.Finalize(); Ref hashTableType = Type::StructureType(hashTableStruct); QualifiedName hashTableName = string("Elf_HashTable"); const string hashTableTypeId = Type::GenerateAutoTypeId("elf", hashTableName); QualifiedName hashTableTypeName = DefineType(hashTableTypeId, hashTableName, hashTableType); DefineDataVariable(m_hashHeader, Type::NamedType(this, hashTableTypeName)); DefineAutoSymbol(new Symbol(DataSymbol, "__elf_hash_table", m_hashHeader, NoBinding)); // Gratuitously create sections for the symbol and string tables if none exist if (!GetSectionsAt(m_auxSymbolTable.offset).size()) AddAutoSection(".dynamic_symtab", m_auxSymbolTable.offset, m_auxSymbolTable.size, ReadOnlyDataSectionSemantics); if (!GetSectionsAt(m_dynamicStringTable.offset).size()) AddAutoSection(".dynamic_strtab", m_dynamicStringTable.offset, m_dynamicStringTable.size, ReadOnlyDataSectionSemantics); } // Parse and create types for ELF GNU hash table if (m_gnuHashHeader) { // try to extract dynamic symbol table size from section information if it exists if (!m_auxSymbolTable.size) { auto sections = GetSectionsAt(m_auxSymbolTable.offset); if (sections.size() && (sections[0]->GetStart() == m_auxSymbolTable.offset)) m_auxSymbolTable.size = sections[0]->GetLength(); else { // TODO section information not available; calculate the dynamic symbol table size from the gnu hash table } } } } catch (ReadException&) { // Skip errors in hash tables m_logger->LogError("ELF hash/symbol table parsing failed"); } try { if (mipsSymValid && (gotStart != 0)) { for (size_t i = 2; i < localMipsSyms; i++) { m_gotEntryLocations.emplace(gotStart + i * (m_elf32 ? 4 : 8)); } for (uint64_t i = firstMipsSym; i < (m_auxSymbolTable.size / (m_elf32 ? 16 : 24)); i++) { uint64_t gotEntry = gotStart + ((localMipsSyms + i - firstMipsSym) * (m_elf32 ? 4 : 8)); ElfSymbolTableEntry entry; if (!ParseSymbolTableEntry(virtualReader, entry, i, m_auxSymbolTable, m_dynamicStringTable, true)) continue; // TODO dynamic symbol table already parsed above; don't add duplicate entries if (!m_hashHeader) auxSymbolTable.push_back(entry); switch (entry.type) { case ELF_STT_OBJECT: case ELF_STT_NOTYPE: { bool relocationExists = false; for (auto& reloc : relocs) { if (reloc.offset == gotEntry) { relocationExists = true; break; } } if (!relocationExists) { int relocType = m_addressSize == 4 ? 126 /* R_MIPS_COPY */ : 125 /* R_MIPS64_COPY */; relocs.push_back(ELFRelocEntry(gotEntry, i, relocType, 0, 0, false)); } if (entry.section != ELF_SHN_UNDEF) { DefineElfSymbol(DataSymbol, entry.name, gotEntry, true, entry.binding, 4, Type::PointerType(GetDefaultPlatform()->GetArchitecture(), Type::VoidType())->WithConfidence(BN_FULL_CONFIDENCE)); } else DefineElfSymbol(ImportAddressSymbol, entry.name, gotEntry, true, entry.binding, entry.size); break; } case ELF_STT_FUNC: { bool relocationExists = false; for (auto& reloc : relocs) { if (reloc.offset == gotEntry) { relocationExists = true; break; } } if (!relocationExists) { int relocType = m_addressSize == 4 ? 127 /*R_MIPS_JUMP_SLOT*/ : 125 /* R_MIPS64_COPY */; relocs.push_back(ELFRelocEntry(gotEntry, i, relocType, 0, 0, false)); } if (entry.section != ELF_SHN_UNDEF) { DefineElfSymbol(DataSymbol, entry.name, gotEntry, true, entry.binding, 4, Type::PointerType(GetDefaultPlatform()->GetArchitecture(), Type::FunctionType(Type::IntegerType(GetDefaultPlatform()->GetArchitecture()->GetAddressSize(), true), GetDefaultPlatform()->GetDefaultCallingConvention(), vector())->WithConfidence(0))); } else DefineElfSymbol(ImportAddressSymbol, entry.name, gotEntry, true, entry.binding, entry.size); // TODO for now create associated PLT entry if it exists. At some point we could extend the detection in RecognizeELFPLTEntries in arch_mips. Ref sym = GetSymbolByAddress(gotEntry); if (entry.value && sym && (sym->GetType() == ImportAddressSymbol)) { uint64_t adjustedAddress = entry.value + imageBaseAdjustment; Ref targetPlatform = platform->GetAssociatedPlatformByAddress(adjustedAddress); Ref func = AddFunctionForAnalysis(targetPlatform, adjustedAddress); if (func) { Ref funcSym = new Symbol(ImportedFunctionSymbol, sym->GetShortName(), sym->GetFullName(), sym->GetRawName(), adjustedAddress, NoBinding, sym->GetNameSpace(), sym->GetOrdinal()); DefineAutoSymbol(funcSym); func->ApplyImportedTypes(funcSym); } } break; } default: m_logger->LogDebug("ELF symbol type of %d not handled.", entry.type); break; } } } } catch (ReadException&) { // Symbol table is not critical to execution, skip errors m_logger->LogError("ELF symbol table invalid"); } // No longer need to look up symbols during creation, start a parallelized queue for // demangling and preparing symbols. m_symbolQueue = new SymbolQueue(); // Now define symbols and resolve relocations vector combinedSymbolTable; if (symbolTable.size() > 1) combinedSymbolTable.insert(combinedSymbolTable.end(), symbolTable.begin() + 1, symbolTable.end()); if (dynamicSymbolTable.size() > 1) combinedSymbolTable.insert(combinedSymbolTable.end(), dynamicSymbolTable.begin() + 1, dynamicSymbolTable.end()); if (auxSymbolTable.size() > 1) combinedSymbolTable.insert(combinedSymbolTable.end(), auxSymbolTable.begin() + 1, auxSymbolTable.end()); // Walk the symbol table a first time to collect the information we need to create a .common section size_t commonSectionSize = 0; for (auto entry = combinedSymbolTable.begin(); entry != combinedSymbolTable.end(); entry++) { if (entry->section == ELF_SHN_COMMON) { // account for required alignment, stored in entry->value; auto alignedExistingSize = commonSectionSize + (entry->value - 1); alignedExistingSize &= ~(entry->value - 1); commonSectionSize = alignedExistingSize + entry->size; } } // If the common section exists create a mock segment/section. size_t commonSegmentStartAddr = 0; if (commonSectionSize > 0) { // Find the end of the existing segment definitions to stick the SHN_COMMON segment for (const auto& segment : GetSegments()) { if (commonSegmentStartAddr < segment->GetEnd()) { commonSegmentStartAddr = segment->GetEnd(); } } // Align the common segment to 16 bytes commonSegmentStartAddr = (commonSegmentStartAddr + 0xf) & (~0xf); AddAutoSegment(commonSegmentStartAddr, commonSectionSize, 0, 0, SegmentReadable | SegmentWritable); AddAutoSection(".common", commonSegmentStartAddr, commonSectionSize, ReadWriteDataSectionSemantics); } size_t commonSegmentOffset = 0; auto allSections = GetSections(); for (auto entry = combinedSymbolTable.begin(); entry != combinedSymbolTable.end(); entry++) { if (entry->section == ELF_SHN_COMMON) { // Common symbols are special as their entry value holds the alignment of the entry instead of an offset. auto alignedExistingOffset = commonSegmentOffset + (entry->value - 1); alignedExistingOffset &= ~(entry->value - 1); DefineElfSymbol(DataSymbol, entry->name, commonSegmentStartAddr + alignedExistingOffset, false, entry->binding, entry->size); commonSegmentOffset = alignedExistingOffset + entry->size; continue; } if (m_objectFile) { if (entry->section >= m_elfSections.size()) continue; // Object files "entry.value" is section relative uint64_t adjustedSectionAddr = m_elfSections[entry->section].address + imageBaseAdjustment; // Get the section who contains the adjustedSectionAddr // We avoid using GetSectionAt() here as when the list of sections grows large calling this in an // inner loop can be very slow. for (const auto& section : allSections) { if (adjustedSectionAddr >= section->GetStart() && adjustedSectionAddr < section->GetEnd()) { entry->value += section->GetStart(); break; } } } else entry->value += imageBaseAdjustment; if (entry->section == ELF_SHN_UNDEF) { DefineElfSymbol(ExternalSymbol, entry->name, 0, false, entry->binding, entry->size); } else { switch (entry->type) { case ELF_STT_GNU_IFUNC: // Only handle this symbol type if the platform is a linux. Otherwise, we don't know what it is. if (GetDefaultPlatform()->GetName().rfind("linux", 0) != 0) goto unknownType; DefineElfSymbol(FunctionSymbol, entry->name, entry->value, false, entry->binding); break; case ELF_STT_FUNC: DefineElfSymbol(FunctionSymbol, entry->name, entry->value, false, entry->binding); break; case ELF_STT_TLS: /* - only create Binja symbols for .symtab (not .dynsym) symbols - ignore mapping symbols, all is assumed data - ignore 0-length symbols (like _TLS_MODULE_BASE_) that are just informative */ if (entry->dynamic || entry->size == 0 || entry->name == "$d") /* is the value a valid offset in the TLS template? */ if (m_tlsSegment.virtualAddress == 0 || (entry->value + entry->size) > m_tlsSegment.memorySize) break; /* the value is the offset into the TLS template, specified by program header type 7 (PT_TLS) */ DefineElfSymbol(DataSymbol, entry->name, m_tlsSegment.virtualAddress + entry->value, false, entry->binding, entry->size); break; case ELF_STT_NOTYPE: // TODO: ARM specific local entry handling to be moved to architecture extension for ELF if (entry->binding == LocalBinding && In(m_arch->GetName(), {"aarch64", "armv7", "armv7eb", "thumb2", "thumb2eb"})) { // ARM Mapping Symbols // $a labels the first byte of a sequence of ARM instructions. Its type is STT_FUNC. // $b labels a Thumb BL instruction. Its type is STT_FUNC. // $d labels the first byte of a sequence of data items. Its type is STT_OBJECT. // $f labels a function pointer constant (static pointer to code). Its type is STT_OBJECT. // $t labels the first byte of a sequence of Thumb instructions. Its type is STT_FUNC. // $*. is an optional long form // AArch64 Mapping Symbols // $x labels start of sequence of A64 instructions // $d labels start of sequence of data items // $*. is an optional long form bool isMappingSymbol = false; bool isMappingFunctionSymbol = false; string entryName(entry->name); uint64_t target = entry->value; if (m_arch->GetName() == "aarch64") { if (!entryName.rfind("$x", 0)) isMappingSymbol = isMappingFunctionSymbol = true; else if (!entryName.rfind("$d", 0)) isMappingSymbol = true; } else { if (!entryName.rfind("$a", 0)) isMappingSymbol = isMappingFunctionSymbol = true; else if (!entryName.rfind("$b", 0) || !entryName.rfind("$t", 0)) { target |= 1; isMappingSymbol = isMappingFunctionSymbol = true; } else if (!entryName.rfind("$d", 0) || !entryName.rfind("$f", 0)) isMappingSymbol = true; } if (isMappingSymbol) { if (!m_elfSections[entry->section].address) // only add artifacts for mapped sections break; // Note: It appears that several '$a' or '$t' mapping symbols to not always indicate function starts. Occasionally, an address is marked // immediately after a literal pool which is not a function. We explicitly allow mapping symbols for .plt sections for now. if (isMappingFunctionSymbol && (sectionNames[entry->section] == ".plt")) { Ref targetPlatform = platform->GetAssociatedPlatformByAddress(target); AddFunctionForAnalysis(targetPlatform, target); } // else // TODO $d and %f // m_logger->LogError("TODO: %s %p", entryName.c_str(), entry->value); // handle long form symbols if (auto pos = entryName.find(".", 2); (pos != std::string::npos)) { // These mapping symbols do not define actual names if (entryName[0] == '$' && (entryName[1] == 'x' || entryName[1] == 'a' || entryName[1] == 'd' || entryName[1] == 't')) continue; entryName = entryName.substr(pos + 1); if (entryName.size()) DefineElfSymbol(isMappingFunctionSymbol ? FunctionSymbol : DataSymbol, entryName, entry->value, false, entry->binding, entry->size); } break; } } DefineElfSymbol(DataSymbol, entry->name, entry->value, false, entry->binding, entry->size); break; case ELF_STT_OBJECT: DefineElfSymbol(DataSymbol, entry->name, entry->value, false, entry->binding, entry->size); break; default: unknownType: m_logger->LogDebug("ELF symbol type of %d not handled.", entry->type); break; } } } ParseMiniDebugInfo(); // Process the queued symbols m_symbolQueue->Process(); delete m_symbolQueue; m_symbolQueue = nullptr; bulkSymbolModification.End(); auto relocHandler = m_arch->GetRelocationHandler("ELF"); if (relocHandler) { try { for (auto& reloc: relocs) { BNRelocationInfo relocInfo; memset(&relocInfo, 0, sizeof(BNRelocationInfo)); if (m_objectFile) { // In unlinked images reloc.offset is relative to the info section specified if (reloc.sectionIdx >= m_elfSections.size()) throw ReadException(); auto sectionName = ReadStringTable(reader, m_sectionStringTable, m_elfSections[reloc.sectionIdx].name); auto sec = GetSectionByName(sectionName); if (!sec) continue; reloc.offset += sec->GetStart() - imageBaseAdjustment; } relocInfo.symbolIndex = reloc.sym; relocInfo.address = reloc.offset; relocInfo.nativeType = reloc.relocType; relocInfo.addend = reloc.addend; relocInfo.implicitAddend = reloc.implicit; relocInfo.base = baseAddress; virtualReader.Seek(relocInfo.address); memset(relocInfo.relocationDataCache, 0, sizeof(relocInfo.relocationDataCache)); virtualReader.TryRead(relocInfo.relocationDataCache, MAX_RELOCATION_SIZE); m_relocationInfo.push_back(relocInfo); if (isArmV7) { if(reloc.relocType == R_ARM_TLS_DTPOFF32) tlsOffsets.push_back(reloc.offset); else if(reloc.relocType == R_ARM_TLS_DTPMOD32) tlsModuleStarts.push_back(reloc.offset); } else if (m_arch && (m_arch->GetName() == "x86_64")) { if (reloc.relocType == R_X86_64_DTPOFF64) tlsOffsets.push_back(reloc.offset); else if (reloc.relocType == R_X86_64_DTPMOD64) tlsModuleStarts.push_back(reloc.offset); } } if (relocHandler->GetRelocationInfo(this, m_arch, m_relocationInfo)) { vector* symTable = &symbolTable; if (!m_objectFile) symTable = &dynamicSymbolTable; size_t anonymousEntryCount = 0; for (auto& relocInfo : m_relocationInfo) { if (relocInfo.type == IgnoredRelocation) continue; if ((relocInfo.symbolIndex == 0) && (m_arch && (m_arch->GetName() == "x86")) && (relocInfo.nativeType == R_386_IRELATIVE)) { uint64_t addend = relocInfo.addend; if (relocInfo.implicitAddend && (relocInfo.size > 0) && (relocInfo.size <= sizeof(addend))) memcpy(&addend, relocInfo.relocationDataCache, relocInfo.size); uint64_t target = addend; if (imageBaseAdjustment != 0) target += imageBaseAdjustment; if (auto targetSymbol = GetSymbolByAddress(target); targetSymbol && !GetSymbolByAddress(relocInfo.address)) DefineElfSymbol(ImportAddressSymbol, targetSymbol->GetRawName(), relocInfo.address, true, targetSymbol->GetBinding()); } // Define absolute relocations with no symbol specified such as R_PPC_RELATIVE and R_ARM_IRELATIVE // Define unhandled relocations in order to detect them and avoid creating functions at invalid target addresses if ((relocInfo.symbolIndex == 0) || (relocInfo.type == UnhandledRelocation)) { relocInfo.baseRelative = imageBaseAdjustment != 0; DefineRelocation(m_arch, relocInfo, imageBaseAdjustment, relocInfo.address); } else { ElfSymbolTableEntry entry; if (relocInfo.symbolIndex < symTable->size()) entry = (*symTable)[relocInfo.symbolIndex]; else if (!ParseSymbolTableEntry(virtualReader, entry, relocInfo.symbolIndex, m_auxSymbolTable, m_dynamicStringTable, true)) continue; if (relocInfo.type == ELFGlobalRelocationType) DefineElfSymbol(ImportAddressSymbol, entry.name, relocInfo.address, true, entry.binding, entry.size); else if (relocInfo.type == ELFCopyRelocationType) DefineElfSymbol(ImportedDataSymbol, entry.name, relocInfo.address, false, entry.binding, entry.size); else if (relocInfo.type == ELFJumpSlotRelocationType) DefineElfSymbol(ImportAddressSymbol, entry.name, relocInfo.address, true, entry.binding, entry.size); if (entry.type == ELF_STT_SECTION) { // Section relative relocation if (auto section = GetSectionByName(entry.name); section) { DefineRelocation(m_arch, relocInfo, section->GetStart(), relocInfo.address); continue; } } else if (!entry.section) { // handle anonymous symbol generation if (!entry.name.size()) { entry.name = "anonymous_"; if (entry.type == ELF_STT_FUNC) entry.name += "func"; else if (entry.type == ELF_STT_OBJECT) entry.name += "object"; else entry.name += "data"; entry.name += "_"; switch(entry.binding) { case NoBinding: entry.name += "bind_none"; break; case LocalBinding: entry.name += "bind_local"; break; case GlobalBinding: entry.name += "bind_global"; break; case WeakBinding: entry.name += "bind_weak"; break; default: break; } entry.name += "_"; entry.name += std::to_string(anonymousEntryCount++); DefineElfSymbol(ExternalSymbol, entry.name, 0, false, entry.binding, entry.size); } // section undefined so query for external symbol directly auto symbol = GetSymbolByRawName(entry.name, GetExternalNameSpace()); if (symbol) { DefineRelocation(m_arch, relocInfo, symbol, relocInfo.address); continue; } } else if (entry.section < m_elfSections.size()) { // symbol is relative to a section, look up by address instead of name to avoid ambiguity uint64_t target = m_elfSections[entry.section].address + entry.value; auto symbol = GetSymbolByAddress(target); if (symbol) { DefineRelocation(m_arch, relocInfo, symbol, relocInfo.address); continue; } } // retrieve first symbol that is not a symbol relocation auto symbols = GetSymbolsByName(entry.name); for (const auto& symbol : symbols) { if (symbol->GetAddress() == relocInfo.address) continue; DefineRelocation(m_arch, relocInfo, symbol, relocInfo.address); break; } } } } } catch (ReadException&) { // Skip errors in relocation tables m_logger->LogError("Failed to parse relocations"); } } // Add additional function starts, after symbols have been processed for (const auto& section : GetSections()) { if ((section->GetLength() > 0) && ((section->GetName() == ".init") || (section->GetName() == ".fini"))) { string autoSectionName = section->GetName(); autoSectionName.replace(0, 1, "_"); auto funcs = GetAnalysisFunctionsForAddress(section->GetStart()); if (!m_backedByDatabase) // Don't create symbols that are present in the database snapshot now { auto symbol = GetSymbolByAddress(section->GetStart()); if (!symbol) DefineAutoSymbol(new Symbol(FunctionSymbol, autoSectionName, section->GetStart(), GlobalBinding)); } // Prefer function creation via recursive descent when encountering mixed architecture binaries where the entry point arch differs from the file arch if ((funcs.size() == 0) && (entryPointArch == m_arch)) { AddFunctionForAnalysis(GetDefaultPlatform(), section->GetStart()); m_logger->LogDebug("Adding function start: %#" PRIx64 "\n", section->GetStart()); } } else if (!(section->GetLength() % m_addressSize) && ((section->GetName() == ".init_array") || (section->GetName() == ".fini_array") || (section->GetName() == ".ctors") || (section->GetName() == ".dtors"))) { // define a function pointer array: void (*init_array[])(void) auto function = Type::FunctionType(Type::VoidType(), platform->GetDefaultCallingConvention(), vector())->WithConfidence(0); auto function_pointer = Type::PointerType(m_addressSize, function)->WithConfidence(0); auto array = Type::ArrayType(function_pointer, section->GetLength() / m_addressSize); DefineDataVariable(section->GetStart(), array); // trim the first '.' from the section name string autoSectionName = section->GetName().substr(1); // define a symbol for the array if (auto symbol = GetSymbolByAddress(section->GetStart()); !symbol) DefineAutoSymbol(new Symbol(DataSymbol, autoSectionName, section->GetStart(), NoBinding)); virtualReader.Seek(section->GetStart()); uint64_t maxAddress = -1; if (GetAddressSize() < 8) maxAddress = (1ULL << (8 * GetAddressSize())) - 1; for (uint32_t i = 0; i < section->GetLength() / m_addressSize; i++) { uint64_t entry; try { entry = virtualReader.ReadPointer(); // ctor and dtor sections often contain address 0x0 and 0xffffffff as markers, we need to ignore // them if ((entry == 0) || (entry == maxAddress)) continue; } catch (const ReadException& r) { m_logger->LogWarn("Fail to read pointer at %#" PRIx64 " while parsing section %s", virtualReader.GetOffset(), autoSectionName.c_str()); break; } if (entry) { entry += imageBaseAdjustment; Ref entryArch = entryPointArch->GetAssociatedArchitectureByAddress(entry); if (entryArch != entryPointArch) { auto func = AddFunctionForAnalysis(platform->GetRelatedPlatform(entryArch), entry); if (func) { AddToEntryFunctions(func); } } else { auto func = AddFunctionForAnalysis(platform, entry); if (func) { AddToEntryFunctions(func); } } m_logger->LogDebug("Adding function start: %#" PRIx64 "\n", entry); // name functions in .init_array, .fini_array, .ctors and .dtors if (!GetSymbolByAddress(entry)) { if (section->GetName() == ".init_array") DefineElfSymbol(FunctionSymbol, "_INIT_" + std::to_string(i), entry, false, GlobalBinding); else if (section->GetName() == ".fini_array") DefineElfSymbol(FunctionSymbol, "_FINI_" + std::to_string(i), entry, false, GlobalBinding); else if (section->GetName() == ".ctors") DefineElfSymbol(FunctionSymbol, "_CTOR_" + std::to_string(i), entry, false, GlobalBinding); else if (section->GetName() == ".dtors") DefineElfSymbol(FunctionSymbol, "_DTOR_" + std::to_string(i), entry, false, GlobalBinding); } } } } } if (m_gotEntryLocations.size() > 0) { Ref
got = GetSectionByName(".got"); if (!got) { m_logger->LogWarn( "ELF view did not find a .got section despite detected relocations; " "attempting to create sections with appropriate semantics"); // Ensure the collected GOT entry locations include the program header specified GOT address. if (gotStart) { m_gotEntryLocations.emplace(gotStart); // A common setup observed is GOT[0] being the resolver, GOT[1] a constant, then pointers. // If gotStart and a collected address sandwich a constant, include the constant. if (m_gotEntryLocations.find(gotStart + 2 * m_addressSize) != m_gotEntryLocations.end()) m_gotEntryLocations.emplace(gotStart + m_addressSize); } map gotSectionsToCreate; auto it = m_gotEntryLocations.begin(); uint64_t start = *it; uint64_t next = start + m_addressSize; it++; while (true) { bool end = (it == m_gotEntryLocations.end()); if (end || (*it != next)) { gotSectionsToCreate[start] = next - start; if (end) break; start = *it; next = start; } next += m_addressSize; it++; } for (auto& s : gotSectionsToCreate) { // Don't try creating a section if it starts in an already-created section. if (GetSectionsAt(s.first).size() > 0) continue; stringstream ss; ss << ".got_recovered_" << std::hex << s.first; AddAutoSection(ss.str(), s.first, s.second, ReadOnlyDataSectionSemantics); } } // Perform fixup processing on the local GOT entries if the view is relocatable. if (m_relocatable) { uint64_t lastLocalGotEntry = gotStart + (localMipsSyms - 1) * (m_elf32 ? 4 : 8); for (auto gotEntry : m_gotEntryLocations) { if (gotEntry > lastLocalGotEntry) break; virtualReader.Seek(gotEntry); auto target = virtualReader.ReadPointer(); BNRelocationInfo relocInfo; memset(&relocInfo, 0, sizeof(BNRelocationInfo)); relocInfo.address = gotEntry; relocInfo.size = m_addressSize; relocInfo.nativeType = m_addressSize == 4 ? 127 /*R_MIPS_JUMP_SLOT*/ : 125 /* R_MIPS64_COPY */; DefineRelocation(m_arch, relocInfo, target + baseAddress, relocInfo.address); } } } // Sometimes ELF will specify Thumb entry points w/o the bottom bit set // To deal with this we delay adding entry points until after symbols have been resolved // and ALL the functions have been created. This allows us to query the existing functions // platform. All in an effort to not create a function with the wrong architecture if (entryPointAddress && (entryPointAddress != GetStart())) { auto func = GetAnalysisFunctionsForAddress(entryPointAddress); if (func.size() == 1) AddEntryPointForAnalysis(func[0]->GetPlatform(), entryPointAddress); else AddEntryPointForAnalysis(GetDefaultPlatform(), entryPointAddress); } // Add a symbol for the entry point if (entryPointAddress && (entryPointAddress != GetStart()) && !GetSymbolByAddress(entryPointAddress)) DefineAutoSymbol(new Symbol(FunctionSymbol, "_start", entryPointAddress, GlobalBinding)); // Create type for ELF identification const string structNamePrefix = (m_addressSize == 4) ? "Elf32_" : "Elf64_"; StructureBuilder identBuilder; identBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 4), "signature"); identBuilder.AddMember(Type::IntegerType(1, false), "file_class"); identBuilder.AddMember(Type::IntegerType(1, false), "encoding"); identBuilder.AddMember(Type::IntegerType(1, false), "version"); identBuilder.AddMember(Type::IntegerType(1, false), "os"); identBuilder.AddMember(Type::IntegerType(1, false), "abi_version"); identBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 7), "pad"); Ref identStruct = identBuilder.Finalize(); Ref identType = Type::StructureType(identStruct); QualifiedName identStructName = structNamePrefix + "Ident"; const string identStructTypeId = Type::GenerateAutoTypeId("elf", identStructName); QualifiedName elfIdentStructName = DefineType(identStructTypeId, identStructName, identType); QualifiedName rawIdentStructName = GetParentView()->DefineType(identStructTypeId, identStructName, identType); // Create enum for ELF header machine EnumerationBuilder elfHeaderMachineBuilder; elfHeaderMachineBuilder.AddMemberWithValue("EM_NONE", EM_NONE); elfHeaderMachineBuilder.AddMemberWithValue("EM_M32", EM_M32); elfHeaderMachineBuilder.AddMemberWithValue("EM_SPARC", EM_SPARC); elfHeaderMachineBuilder.AddMemberWithValue("EM_386", EM_386); elfHeaderMachineBuilder.AddMemberWithValue("EM_68K", EM_68K); elfHeaderMachineBuilder.AddMemberWithValue("EM_88K", EM_88K); elfHeaderMachineBuilder.AddMemberWithValue("EM_860", EM_860); elfHeaderMachineBuilder.AddMemberWithValue("EM_MIPS", EM_MIPS); elfHeaderMachineBuilder.AddMemberWithValue("EM_S370", EM_S370); elfHeaderMachineBuilder.AddMemberWithValue("EM_MIPS_RS3_LE", EM_MIPS_RS3_LE); elfHeaderMachineBuilder.AddMemberWithValue("EM_PARISC", EM_PARISC); elfHeaderMachineBuilder.AddMemberWithValue("EM_VPP500", EM_VPP500); elfHeaderMachineBuilder.AddMemberWithValue("EM_SPARC32PLUS", EM_SPARC32PLUS); elfHeaderMachineBuilder.AddMemberWithValue("EM_960", EM_960); elfHeaderMachineBuilder.AddMemberWithValue("EM_PPC", EM_PPC); elfHeaderMachineBuilder.AddMemberWithValue("EM_PPC64", EM_PPC64); elfHeaderMachineBuilder.AddMemberWithValue("EM_S390", EM_S390); elfHeaderMachineBuilder.AddMemberWithValue("EM_V800", EM_V800); elfHeaderMachineBuilder.AddMemberWithValue("EM_FR20", EM_FR20); elfHeaderMachineBuilder.AddMemberWithValue("EM_RH32", EM_RH32); elfHeaderMachineBuilder.AddMemberWithValue("EM_RCE", EM_RCE); elfHeaderMachineBuilder.AddMemberWithValue("EM_ARM", EM_ARM); elfHeaderMachineBuilder.AddMemberWithValue("EM_FAKE_ALPHA", EM_FAKE_ALPHA); elfHeaderMachineBuilder.AddMemberWithValue("EM_SH", EM_SH); elfHeaderMachineBuilder.AddMemberWithValue("EM_SPARCV9", EM_SPARCV9); elfHeaderMachineBuilder.AddMemberWithValue("EM_TRICORE", EM_TRICORE); elfHeaderMachineBuilder.AddMemberWithValue("EM_ARC", EM_ARC); elfHeaderMachineBuilder.AddMemberWithValue("EM_H8_300", EM_H8_300); elfHeaderMachineBuilder.AddMemberWithValue("EM_H8_300H", EM_H8_300H); elfHeaderMachineBuilder.AddMemberWithValue("EM_H8S", EM_H8S); elfHeaderMachineBuilder.AddMemberWithValue("EM_H8_500", EM_H8_500); elfHeaderMachineBuilder.AddMemberWithValue("EM_IA_64", EM_IA_64); elfHeaderMachineBuilder.AddMemberWithValue("EM_MIPS_X", EM_MIPS_X); elfHeaderMachineBuilder.AddMemberWithValue("EM_COLDFIRE", EM_COLDFIRE); elfHeaderMachineBuilder.AddMemberWithValue("EM_68HC12", EM_68HC12); elfHeaderMachineBuilder.AddMemberWithValue("EM_MMA", EM_MMA); elfHeaderMachineBuilder.AddMemberWithValue("EM_PCP", EM_PCP); elfHeaderMachineBuilder.AddMemberWithValue("EM_NCPU", EM_NCPU); elfHeaderMachineBuilder.AddMemberWithValue("EM_NDR1", EM_NDR1); elfHeaderMachineBuilder.AddMemberWithValue("EM_STARCORE", EM_STARCORE); elfHeaderMachineBuilder.AddMemberWithValue("EM_ME16", EM_ME16); elfHeaderMachineBuilder.AddMemberWithValue("EM_ST100", EM_ST100); elfHeaderMachineBuilder.AddMemberWithValue("EM_TINYJ", EM_TINYJ); elfHeaderMachineBuilder.AddMemberWithValue("EM_X86_64", EM_X86_64); elfHeaderMachineBuilder.AddMemberWithValue("EM_PDSP", EM_PDSP); elfHeaderMachineBuilder.AddMemberWithValue("EM_FX66", EM_FX66); elfHeaderMachineBuilder.AddMemberWithValue("EM_ST9PLUS", EM_ST9PLUS); elfHeaderMachineBuilder.AddMemberWithValue("EM_ST7", EM_ST7); elfHeaderMachineBuilder.AddMemberWithValue("EM_68HC16", EM_68HC16); elfHeaderMachineBuilder.AddMemberWithValue("EM_68HC11", EM_68HC11); elfHeaderMachineBuilder.AddMemberWithValue("EM_68HC08", EM_68HC08); elfHeaderMachineBuilder.AddMemberWithValue("EM_68HC05", EM_68HC05); elfHeaderMachineBuilder.AddMemberWithValue("EM_SVX", EM_SVX); elfHeaderMachineBuilder.AddMemberWithValue("EM_ST19", EM_ST19); elfHeaderMachineBuilder.AddMemberWithValue("EM_VAX", EM_VAX); elfHeaderMachineBuilder.AddMemberWithValue("EM_CRIS", EM_CRIS); elfHeaderMachineBuilder.AddMemberWithValue("EM_JAVELIN", EM_JAVELIN); elfHeaderMachineBuilder.AddMemberWithValue("EM_FIREPATH", EM_FIREPATH); elfHeaderMachineBuilder.AddMemberWithValue("EM_ZSP", EM_ZSP); elfHeaderMachineBuilder.AddMemberWithValue("EM_MMIX", EM_MMIX); elfHeaderMachineBuilder.AddMemberWithValue("EM_HUANY", EM_HUANY); elfHeaderMachineBuilder.AddMemberWithValue("EM_PRISM", EM_PRISM); elfHeaderMachineBuilder.AddMemberWithValue("EM_AVR", EM_AVR); elfHeaderMachineBuilder.AddMemberWithValue("EM_FR30", EM_FR30); elfHeaderMachineBuilder.AddMemberWithValue("EM_D10V", EM_D10V); elfHeaderMachineBuilder.AddMemberWithValue("EM_D30V", EM_D30V); elfHeaderMachineBuilder.AddMemberWithValue("EM_V850", EM_V850); elfHeaderMachineBuilder.AddMemberWithValue("EM_M32R", EM_M32R); elfHeaderMachineBuilder.AddMemberWithValue("EM_MN10300", EM_MN10300); elfHeaderMachineBuilder.AddMemberWithValue("EM_MN10200", EM_MN10200); elfHeaderMachineBuilder.AddMemberWithValue("EM_PJ", EM_PJ); elfHeaderMachineBuilder.AddMemberWithValue("EM_OPENRISC", EM_OPENRISC); elfHeaderMachineBuilder.AddMemberWithValue("EM_ARC_A5", EM_ARC_A5); elfHeaderMachineBuilder.AddMemberWithValue("EM_XTENSA", EM_XTENSA); elfHeaderMachineBuilder.AddMemberWithValue("EM_ALTERA_NIOS2", EM_ALTERA_NIOS2); elfHeaderMachineBuilder.AddMemberWithValue("EM_AARCH64", EM_AARCH64); elfHeaderMachineBuilder.AddMemberWithValue("EM_TILEPRO", EM_TILEPRO); elfHeaderMachineBuilder.AddMemberWithValue("EM_MICROBLAZE", EM_MICROBLAZE); elfHeaderMachineBuilder.AddMemberWithValue("EM_TILEGX", EM_TILEGX); elfHeaderMachineBuilder.AddMemberWithValue("EM_NUM", EM_NUM); Ref elfHeaderMachineEnum = elfHeaderMachineBuilder.Finalize(); Ref elfHeaderMachineEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), elfHeaderMachineEnum, 2, false); const string elfHeaderMachineEnumName = "e_machine"; const string elfHeaderMachineEnumId = Type::GenerateAutoTypeId("elf", elfHeaderMachineEnumName); QualifiedName elfElfHeaderMachineEnumName = DefineType(elfHeaderMachineEnumId, elfHeaderMachineEnumName, elfHeaderMachineEnumType); QualifiedName rawElfHeaderMachineEnumName = GetParentView()->DefineType(elfHeaderMachineEnumId, elfHeaderMachineEnumName, elfHeaderMachineEnumType); // Create enum for ELF header type EnumerationBuilder elfHeaderTypeBuilder; elfHeaderTypeBuilder.AddMemberWithValue("ET_NONE", ET_NONE); elfHeaderTypeBuilder.AddMemberWithValue("ET_REL", ET_REL); elfHeaderTypeBuilder.AddMemberWithValue("ET_EXEC", ET_EXEC); elfHeaderTypeBuilder.AddMemberWithValue("ET_DYN", ET_DYN); elfHeaderTypeBuilder.AddMemberWithValue("ET_CORE", ET_CORE); elfHeaderTypeBuilder.AddMemberWithValue("ET_NUM", ET_NUM); Ref elfHeaderTypeEnum = elfHeaderTypeBuilder.Finalize(); Ref elfHeaderTypeEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), elfHeaderTypeEnum, 2, false); const string elfHeaderTypeEnumName = "e_type"; const string elfHeaderTypeEnumId = Type::GenerateAutoTypeId("elf", elfHeaderTypeEnumName); QualifiedName elfElfHeaderTypeEnumName = DefineType(elfHeaderTypeEnumId, elfHeaderTypeEnumName, elfHeaderTypeEnumType); QualifiedName rawElfHeaderTypeEnumName = GetParentView()->DefineType(elfHeaderTypeEnumId, elfHeaderTypeEnumName, elfHeaderTypeEnumType); // Create type for ELF header StructureBuilder elfHeaderBuilder; elfHeaderBuilder.AddMember(Type::NamedType(this, elfIdentStructName), "ident"); elfHeaderBuilder.AddMember(Type::NamedType(this, elfElfHeaderTypeEnumName), "type"); elfHeaderBuilder.AddMember(Type::NamedType(this, elfElfHeaderMachineEnumName), "machine"); elfHeaderBuilder.AddMember(Type::IntegerType(4, false), "version"); if (platform) { elfHeaderBuilder.AddMember(Type::PointerType(m_addressSize, Type::FunctionType(Type::VoidType(), platform->GetDefaultCallingConvention(), vector())), "entry"); } else { elfHeaderBuilder.AddMember(Type::PointerType(m_addressSize, Type::VoidType()), "entry"); } elfHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "program_header_offset"); elfHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "section_header_offset"); elfHeaderBuilder.AddMember(Type::IntegerType(4, false), "flags"); elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "header_size"); elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "program_header_size"); elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "program_header_count"); elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "section_header_size"); elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "section_header_count"); elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "string_table"); Ref elfHeaderStruct = elfHeaderBuilder.Finalize(); Ref elfHeaderType = Type::StructureType(elfHeaderStruct); QualifiedName headerName = structNamePrefix + "Header"; const string headerTypeId = Type::GenerateAutoTypeId("elf", headerName); QualifiedName elfHeaderName = DefineType(headerTypeId, headerName, elfHeaderType); elfHeaderBuilder.ReplaceMember(0, Type::NamedType(GetParentView(), rawIdentStructName), "ident"); elfHeaderBuilder.ReplaceMember(1, Type::NamedType(GetParentView(), rawElfHeaderTypeEnumName), "type"); elfHeaderBuilder.ReplaceMember(2, Type::NamedType(GetParentView(), rawElfHeaderMachineEnumName), "machine"); elfHeaderBuilder.ReplaceMember(4, Type::IntegerType(m_addressSize, false), "entry"); Ref rawElfHeaderStruct = elfHeaderBuilder.Finalize(); Ref rawElfHeaderType = Type::StructureType(rawElfHeaderStruct); QualifiedName rawHeaderName = GetParentView()->DefineType(headerTypeId, headerName, rawElfHeaderType); // Define variable for ELF header uint64_t addr; if (GetAddressForDataOffset(0, addr)) { DefineDataVariable(addr, Type::NamedType(this, elfHeaderName)); DefineAutoSymbol(new Symbol(DataSymbol, "__elf_header", addr, LocalBinding)); } GetParentView()->DefineDataVariable(0, Type::NamedType(GetParentView(), rawHeaderName)); GetParentView()->DefineAutoSymbol(new Symbol(DataSymbol, "__elf_header", 0, LocalBinding)); // Create enum for ELF program header type EnumerationBuilder programHeaderTypeBuilder; programHeaderTypeBuilder.AddMemberWithValue("PT_NULL", ELF_PT_NULL); programHeaderTypeBuilder.AddMemberWithValue("PT_LOAD", ELF_PT_LOAD); programHeaderTypeBuilder.AddMemberWithValue("PT_DYNAMIC", ELF_PT_DYNAMIC); programHeaderTypeBuilder.AddMemberWithValue("PT_INTERP", ELF_PT_INTERP); programHeaderTypeBuilder.AddMemberWithValue("PT_NOTE", ELF_PT_NOTE); programHeaderTypeBuilder.AddMemberWithValue("PT_SHLIB", ELF_PT_SHLIB); programHeaderTypeBuilder.AddMemberWithValue("PT_PHDR", ELF_PT_PHDR); programHeaderTypeBuilder.AddMemberWithValue("PT_TLS", ELF_PT_TLS); programHeaderTypeBuilder.AddMemberWithValue("PT_NUM", ELF_PT_NUM); programHeaderTypeBuilder.AddMemberWithValue("PT_LOOS", ELF_PT_LOOS); programHeaderTypeBuilder.AddMemberWithValue("PT_GNU_EH_FRAME", ELF_PT_GNU_EH_FRAME); programHeaderTypeBuilder.AddMemberWithValue("PT_GNU_STACK", ELF_PT_GNU_STACK); programHeaderTypeBuilder.AddMemberWithValue("PT_GNU_RELRO", ELF_PT_GNU_RELRO); programHeaderTypeBuilder.AddMemberWithValue("PT_GNU_PROPERTY", ELF_PT_GNU_PROPERTY); programHeaderTypeBuilder.AddMemberWithValue("PT_LOSUNW", ELF_PT_LOSUNW); programHeaderTypeBuilder.AddMemberWithValue("PT_SUNWBSS", ELF_PT_SUNWBSS); programHeaderTypeBuilder.AddMemberWithValue("PT_SUNWSTACK", ELF_PT_SUNWSTACK); programHeaderTypeBuilder.AddMemberWithValue("PT_MIPS_REGINFO", ELF_PT_MIPS_REGINFO); programHeaderTypeBuilder.AddMemberWithValue("PT_MIPS_RTPROC", ELF_PT_MIPS_RTPROC); programHeaderTypeBuilder.AddMemberWithValue("PT_MIPS_OPTIONS", ELF_PT_MIPS_OPTIONS); programHeaderTypeBuilder.AddMemberWithValue("PT_MIPS_ABIFLAGS", ELF_PT_MIPS_ABIFLAGS); Ref programHeaderTypeEnum = programHeaderTypeBuilder.Finalize(); Ref programHeaderTypeEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), programHeaderTypeEnum, 4, false); const string programHeaderTypeEnumName = "p_type"; const string programHeaderTypeEnumId = Type::GenerateAutoTypeId("elf", programHeaderTypeEnumName); QualifiedName elfProgramHeaderTypeEnumName = DefineType(programHeaderTypeEnumId, programHeaderTypeEnumName, programHeaderTypeEnumType); QualifiedName rawProgramHeaderTypeEnumName = GetParentView()->DefineType(programHeaderTypeEnumId, programHeaderTypeEnumName, programHeaderTypeEnumType); // Create enum for ELF program header flags EnumerationBuilder programHeaderFlagsBuilder; programHeaderFlagsBuilder.AddMemberWithValue("PF_X", PF_X); programHeaderFlagsBuilder.AddMemberWithValue("PF_W", PF_W); programHeaderFlagsBuilder.AddMemberWithValue("PF_R", PF_R); Ref programHeaderFlagsEnum = programHeaderFlagsBuilder.Finalize(); Ref programHeaderFlagsEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), programHeaderFlagsEnum, 4, false); const string programHeaderFlagsEnumName = "p_flags"; const string programHeaderFlagsEnumId = Type::GenerateAutoTypeId("elf", programHeaderFlagsEnumName); QualifiedName elfProgramHeaderFlagsEnumName = DefineType(programHeaderFlagsEnumId, programHeaderFlagsEnumName, programHeaderFlagsEnumType); QualifiedName rawProgramHeaderFlagsEnumName = GetParentView()->DefineType(programHeaderFlagsEnumId, programHeaderFlagsEnumName, programHeaderFlagsEnumType); // Create type for ELF program headers StructureBuilder programHeaderBuilder; if (m_addressSize == 4) { programHeaderBuilder.AddMember(Type::NamedType(this, elfProgramHeaderTypeEnumName), "type"); programHeaderBuilder.AddMember(Type::IntegerType(4, false), "offset"); programHeaderBuilder.AddMember(Type::IntegerType(4, false), "virtual_address"); programHeaderBuilder.AddMember(Type::IntegerType(4, false), "physical_address"); programHeaderBuilder.AddMember(Type::IntegerType(4, false), "file_size"); programHeaderBuilder.AddMember(Type::IntegerType(4, false), "memory_size"); programHeaderBuilder.AddMember(Type::NamedType(this, elfProgramHeaderFlagsEnumName), "flags"); programHeaderBuilder.AddMember(Type::IntegerType(4, false), "align"); } else { programHeaderBuilder.AddMember(Type::NamedType(this, elfProgramHeaderTypeEnumName), "type"); programHeaderBuilder.AddMember(Type::NamedType(this, elfProgramHeaderFlagsEnumName), "flags"); programHeaderBuilder.AddMember(Type::IntegerType(8, false), "offset"); programHeaderBuilder.AddMember(Type::IntegerType(8, false), "virtual_address"); programHeaderBuilder.AddMember(Type::IntegerType(8, false), "physical_address"); programHeaderBuilder.AddMember(Type::IntegerType(8, false), "file_size"); programHeaderBuilder.AddMember(Type::IntegerType(8, false), "memory_size"); programHeaderBuilder.AddMember(Type::IntegerType(8, false), "align"); } Ref programHeaderStruct = programHeaderBuilder.Finalize(); Ref programHeaderType = Type::StructureType(programHeaderStruct); QualifiedName programHeaderName = structNamePrefix + "ProgramHeader"; const string programHeaderTypeId = Type::GenerateAutoTypeId("elf", programHeaderName); QualifiedName elfProgramHeaderName = DefineType(programHeaderTypeId, programHeaderName, programHeaderType); if (m_addressSize == 4) { programHeaderBuilder.ReplaceMember(0, Type::NamedType(GetParentView(), rawProgramHeaderTypeEnumName), "type"); programHeaderBuilder.ReplaceMember(6, Type::NamedType(GetParentView(), rawProgramHeaderFlagsEnumName), "flags"); } else { programHeaderBuilder.ReplaceMember(0, Type::NamedType(GetParentView(), rawProgramHeaderTypeEnumName), "type"); programHeaderBuilder.ReplaceMember(1, Type::NamedType(GetParentView(), rawProgramHeaderFlagsEnumName), "flags"); } Ref rawProgramHeaderStruct = programHeaderBuilder.Finalize(); Ref rawProgramHeaderType = Type::StructureType(rawProgramHeaderStruct); QualifiedName rawProgramHeaderName = GetParentView()->DefineType(programHeaderTypeId, programHeaderName, rawProgramHeaderType); // Define variable for ELF program headers if (m_programHeaderCount != 0) { if (GetAddressForDataOffset(m_programHeaderOffset, addr)) { DefineDataVariable(addr, Type::ArrayType(Type::NamedType(this, elfProgramHeaderName), m_programHeaderCount)); DefineAutoSymbol(new Symbol(DataSymbol, "__elf_program_headers", addr, LocalBinding)); } GetParentView()->DefineDataVariable(m_programHeaderOffset, Type::ArrayType(Type::NamedType( GetParentView(), rawProgramHeaderName), m_programHeaderCount)); GetParentView()->DefineAutoSymbol(new Symbol(DataSymbol, "__elf_program_headers", m_programHeaderOffset, LocalBinding)); } // Create enum for ELF section header type EnumerationBuilder sectionHeaderTypeBuilder; sectionHeaderTypeBuilder.AddMemberWithValue("SHT_NULL", ELF_SHT_NULL); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_PROGBITS", ELF_SHT_PROGBITS); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_SYMTAB", ELF_SHT_SYMTAB); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_STRTAB", ELF_SHT_STRTAB); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_RELA", ELF_SHT_RELA); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_HASH", ELF_SHT_HASH); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_DYNAMIC", ELF_SHT_DYNAMIC); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_NOTE", ELF_SHT_NOTE); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_NOBITS", ELF_SHT_NOBITS); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_REL", ELF_SHT_REL); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_SHLIB", ELF_SHT_SHLIB); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_DYNSYM", ELF_SHT_DYNSYM); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_LOUSER", ELF_SHT_LOUSER); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_HIUSER", ELF_SHT_HIUSER); // Machine specific section header types if (m_commonHeader.arch == EM_PARISC) { sectionHeaderTypeBuilder.AddMemberWithValue("SHT_PARISC_EXT", ELF_SHT_EXT); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_PARISC_UNWIND", ELF_SHT_UNWIND); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_PARISC_DOC", ELF_SHT_PARISC_DOC); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_PARISC_ANNOT", ELF_SHT_PARISC_ANNOT); } else if (m_commonHeader.arch == EM_IA_64) { sectionHeaderTypeBuilder.AddMemberWithValue("SHT_IA_64_EXT", ELF_SHT_EXT); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_IA_64_UNWIND", ELF_SHT_UNWIND); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_IA_64_LOPSREG", ELF_SHT_IA_64_LOPSREG); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_IA_64_HIPSREG", ELF_SHT_IA_64_HIPSREG); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_IA_64_PRIORITY_INIT", ELF_SHT_IA_64_PRIORITY_INIT); } else if (m_commonHeader.arch == EM_X86_64) { sectionHeaderTypeBuilder.AddMemberWithValue("SHT_AMD64_UNWIND", ELF_SHT_UNWIND); } else { sectionHeaderTypeBuilder.AddMemberWithValue("SHT_LOPROC", ELF_SHT_LOPROC); sectionHeaderTypeBuilder.AddMemberWithValue("SHT_HIPROC", ELF_SHT_HIPROC); } Ref sectionHeaderTypeEnum = sectionHeaderTypeBuilder.Finalize(); Ref sectionHeaderTypeEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), sectionHeaderTypeEnum, 4, false); const string sectionHeaderTypeEnumName = "sh_type"; const string sectionHeaderTypeEnumId = Type::GenerateAutoTypeId("elf", sectionHeaderTypeEnumName); QualifiedName elfSectionHeaderTypeEnumName = DefineType(sectionHeaderTypeEnumId, sectionHeaderTypeEnumName, sectionHeaderTypeEnumType); QualifiedName rawSectionHeaderTypeEnumName = GetParentView()->DefineType(sectionHeaderTypeEnumId, sectionHeaderTypeEnumName, sectionHeaderTypeEnumType); // Create enum for ELF section header flags EnumerationBuilder sectionHeaderFlagsBuilder; sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_WRITE", ELF_SHF_WRITE); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_ALLOC", ELF_SHF_ALLOC); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_EXECINSTR", ELF_SHF_EXECINSTR); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_MERGE", ELF_SHF_MERGE); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_STRINGS", ELF_SHF_STRINGS); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_INFO_LINK", ELF_SHF_INFO_LINK); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_LINK_ORDER", ELF_SHF_LINK_ORDER); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_OS_NONCONFORMING", ELF_SHF_OS_NONCONFORMING); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_GROUP", ELF_SHF_GROUP); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_TLS", ELF_SHF_TLS); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_COMPRESSED", ELF_SHF_COMPRESSED); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_MASKOS", ELF_SHF_MASKOS); // Machine specific section header flags if (m_commonHeader.arch == EM_PARISC) { sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_PARISC_SHORT", ELF_SHF_PARISC_SHORT); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_PARISC_HUGE", ELF_SHF_PARISC_HUGE); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_PARISC_SBP", ELF_SHF_PARISC_SBP); } else if (m_commonHeader.arch == EM_IA_64) { sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_IA_64_SHORT", ELF_SHF_IA_64_SHORT); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_IA_64_NORECOV", ELF_SHF_IA_64_NORECOV); } else if (m_commonHeader.arch == EM_X86_64) { sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_AMD64_LARGE", ELF_SHF_AMD64_LARGE); } else if (In(m_arch->GetName(), {"aarch64", "armv7", "armv7eb", "thumb2", "thumb2eb"})) { sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_ENTRYSECT", ELF_SHF_ENTRYSECT); sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_COMDEF", ELF_SHF_COMDEF); } else if (In(m_arch->GetName(), {"mipsel32", "mips32"})) { sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_MIPS_GPREL", ELF_SHF_MIPS_GPREL); } else if (In(m_arch->GetName(), {"ppc", "ppc64", "ppc_le", "ppc64_le"})) { sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_EXCLUDE", ELF_SHF_EXCLUDE); } else { sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_MASKPROC", ELF_SHF_MASKPROC); } Ref sectionHeaderFlagsEnum = sectionHeaderFlagsBuilder.Finalize(); Ref sectionHeaderFlagsEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), sectionHeaderFlagsEnum, m_addressSize, false); const string sectionHeaderFlagsEnumName = "sh_flags"; const string sectionHeaderFlagsEnumId = Type::GenerateAutoTypeId("elf", sectionHeaderFlagsEnumName); QualifiedName elfSectionHeaderFlagsEnumName = DefineType(sectionHeaderFlagsEnumId, sectionHeaderFlagsEnumName, sectionHeaderFlagsEnumType); QualifiedName rawSectionHeaderFlagsEnumName = GetParentView()->DefineType(sectionHeaderFlagsEnumId, sectionHeaderFlagsEnumName, sectionHeaderFlagsEnumType); // Create type for ELF section headers StructureBuilder sectionHeaderBuilder; sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "name"); sectionHeaderBuilder.AddMember(Type::NamedType(this, elfSectionHeaderTypeEnumName), "type"); sectionHeaderBuilder.AddMember(Type::NamedType(this, elfSectionHeaderFlagsEnumName), "flags"); sectionHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "address"); sectionHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "offset"); sectionHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "size"); sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "link"); sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "info"); sectionHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "align"); sectionHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "entry_size"); Ref sectionHeaderStruct = sectionHeaderBuilder.Finalize(); Ref sectionHeaderType = Type::StructureType(sectionHeaderStruct); QualifiedName sectionHeaderName = structNamePrefix + "SectionHeader"; const string sectionHeaderTypeId = Type::GenerateAutoTypeId("elf", sectionHeaderName); QualifiedName elfSectionHeaderName = DefineType(sectionHeaderTypeId, sectionHeaderName, sectionHeaderType); sectionHeaderBuilder.ReplaceMember(1, Type::NamedType(GetParentView(), rawSectionHeaderTypeEnumName), "type"); sectionHeaderBuilder.ReplaceMember(2, Type::NamedType(GetParentView(), rawSectionHeaderFlagsEnumName), "flags"); Ref rawSectionHeaderStruct = sectionHeaderBuilder.Finalize(); Ref rawSectionHeaderType = Type::StructureType(rawSectionHeaderStruct); QualifiedName rawSectionHeaderName = GetParentView()->DefineType(sectionHeaderTypeId, sectionHeaderName, rawSectionHeaderType); // Define variable for ELF program headers if (m_sectionHeaderCount != 0) { uint64_t configuredSectionCount = 100; if (viewSettings && viewSettings->Contains("files.elf.maxSectionHeaderCount")) configuredSectionCount = viewSettings->Get("files.elf.maxSectionHeaderCount", this); uint64_t sectionCount = std::min(m_sectionHeaderCount, configuredSectionCount); if (GetAddressForDataOffset(m_sectionHeaderOffset, addr)) { DefineDataVariable(addr, Type::ArrayType(Type::NamedType(this, elfSectionHeaderName), sectionCount)); DefineAutoSymbol(new Symbol(DataSymbol, "__elf_section_headers", addr, LocalBinding)); } GetParentView()->DefineDataVariable(m_sectionHeaderOffset, Type::ArrayType(Type::NamedType(GetParentView(), rawSectionHeaderName), sectionCount)); GetParentView()->DefineAutoSymbol(new Symbol(DataSymbol, "__elf_section_headers", m_sectionHeaderOffset, LocalBinding)); } // Add types for dynamic table if (m_dynamicTable.virtualAddress && m_numDynamicTableEntries) { EnumerationBuilder dynTagEnumBuilder; dynTagEnumBuilder.AddMemberWithValue("DT_NULL", ELF_DT_NULL); dynTagEnumBuilder.AddMemberWithValue("DT_NEEDED", ELF_DT_NEEDED); dynTagEnumBuilder.AddMemberWithValue("DT_PLTRELSZ", ELF_DT_PLTRELSZ); dynTagEnumBuilder.AddMemberWithValue("DT_PLTGOT", ELF_DT_PLTGOT); dynTagEnumBuilder.AddMemberWithValue("DT_HASH", ELF_DT_HASH); dynTagEnumBuilder.AddMemberWithValue("DT_STRTAB", ELF_DT_STRTAB); dynTagEnumBuilder.AddMemberWithValue("DT_SYMTAB", ELF_DT_SYMTAB); dynTagEnumBuilder.AddMemberWithValue("DT_RELA", ELF_DT_RELA); dynTagEnumBuilder.AddMemberWithValue("DT_RELASZ", ELF_DT_RELASZ); dynTagEnumBuilder.AddMemberWithValue("DT_RELAENT", ELF_DT_RELAENT); dynTagEnumBuilder.AddMemberWithValue("DT_STRSZ", ELF_DT_STRSZ); //dynTagEnumBuilder.AddMemberWithValue("DT_DYNSYM", ELF_DT_DYNSYM); dynTagEnumBuilder.AddMemberWithValue("DT_SYMENT", ELF_DT_SYMENT); dynTagEnumBuilder.AddMemberWithValue("DT_INIT", ELF_DT_INIT); dynTagEnumBuilder.AddMemberWithValue("DT_FINI", ELF_DT_FINI); dynTagEnumBuilder.AddMemberWithValue("DT_SONAME", ELF_DT_SONAME); dynTagEnumBuilder.AddMemberWithValue("DT_RPATH", ELF_DT_RPATH); dynTagEnumBuilder.AddMemberWithValue("DT_SYMBOLIC", ELF_DT_SYMBOLIC); dynTagEnumBuilder.AddMemberWithValue("DT_REL", ELF_DT_REL); dynTagEnumBuilder.AddMemberWithValue("DT_RELSZ", ELF_DT_RELSZ); dynTagEnumBuilder.AddMemberWithValue("DT_RELENT", ELF_DT_RELENT); dynTagEnumBuilder.AddMemberWithValue("DT_PLTREL", ELF_DT_PLTREL); dynTagEnumBuilder.AddMemberWithValue("DT_DEBUG", ELF_DT_DEBUG); dynTagEnumBuilder.AddMemberWithValue("DT_TEXTREL", ELF_DT_TEXTREL); dynTagEnumBuilder.AddMemberWithValue("DT_JMPREL", ELF_DT_JMPREL); dynTagEnumBuilder.AddMemberWithValue("DT_BIND_NOW", ELF_DT_BIND_NOW); dynTagEnumBuilder.AddMemberWithValue("DT_INIT_ARRAY", ELF_DT_INIT_ARRAY); dynTagEnumBuilder.AddMemberWithValue("DT_FINI_ARRAY", ELF_DT_FINI_ARRAY); dynTagEnumBuilder.AddMemberWithValue("DT_INIT_ARRAYSZ", ELF_DT_INIT_ARRAYSZ); dynTagEnumBuilder.AddMemberWithValue("DT_FINI_ARRAYSZ", ELF_DT_FINI_ARRAYSZ); dynTagEnumBuilder.AddMemberWithValue("DT_RUNPATH", ELF_DT_RUNPATH); dynTagEnumBuilder.AddMemberWithValue("DT_FLAGS", ELF_DT_FLAGS); dynTagEnumBuilder.AddMemberWithValue("DT_ENCODING", ELF_DT_ENCODING); dynTagEnumBuilder.AddMemberWithValue("DT_PREINIT_ARRAY", ELF_DT_PREINIT_ARRAY); dynTagEnumBuilder.AddMemberWithValue("DT_PREINIT_ARRAYSZ", ELF_DT_PREINIT_ARRAYSZ); dynTagEnumBuilder.AddMemberWithValue("DT_LOOS", ELF_DT_LOOS); dynTagEnumBuilder.AddMemberWithValue("DT_SUNW_RTLDINF", ELF_DT_SUNW_RTLDINF); dynTagEnumBuilder.AddMemberWithValue("DT_HIOS", ELF_DT_HIOS); dynTagEnumBuilder.AddMemberWithValue("DT_VALRNGLO", ELF_DT_VALRNGLO); dynTagEnumBuilder.AddMemberWithValue("DT_CHECKSUM", ELF_DT_CHECKSUM); dynTagEnumBuilder.AddMemberWithValue("DT_PLTPADSZ", ELF_DT_PLTPADSZ); dynTagEnumBuilder.AddMemberWithValue("DT_MOVEENT", ELF_DT_MOVEEN); dynTagEnumBuilder.AddMemberWithValue("DT_MOVESZ", ELF_DT_MOVES); dynTagEnumBuilder.AddMemberWithValue("DT_FEATURE_1", ELF_DT_FEATURE_1); dynTagEnumBuilder.AddMemberWithValue("DT_POSFLAG_1", ELF_DT_POSFLAG_1); dynTagEnumBuilder.AddMemberWithValue("DT_SYMINSZ", ELF_DT_SYMINSZ); dynTagEnumBuilder.AddMemberWithValue("DT_SYMINENT", ELF_DT_SYMINENT); dynTagEnumBuilder.AddMemberWithValue("DT_VALRNGHI", ELF_DT_VALRNGH); dynTagEnumBuilder.AddMemberWithValue("DT_ADDRRNGLO", ELF_DT_ADDRRNGLO); dynTagEnumBuilder.AddMemberWithValue("DT_GNU_HASH", ELF_DT_GNU_HASH); dynTagEnumBuilder.AddMemberWithValue("DT_CONFIG", ELF_DT_CONFIG); dynTagEnumBuilder.AddMemberWithValue("DT_DEPAUDIT", ELF_DT_DEPAUDIT); dynTagEnumBuilder.AddMemberWithValue("DT_AUDIT", ELF_DT_AUDIT); dynTagEnumBuilder.AddMemberWithValue("DT_PLTPAD", ELF_DT_PLTPAD); dynTagEnumBuilder.AddMemberWithValue("DT_MOVETAB", ELF_DT_MOVETAB); dynTagEnumBuilder.AddMemberWithValue("DT_SYMINFO", ELF_DT_SYMINFO); dynTagEnumBuilder.AddMemberWithValue("DT_ADDRRNGHI", ELF_DT_ADDRRNGHI); dynTagEnumBuilder.AddMemberWithValue("DT_RELACOUNT", ELF_DT_RELACOUNT); dynTagEnumBuilder.AddMemberWithValue("DT_RELCOUNT", ELF_DT_RELCOUNT); dynTagEnumBuilder.AddMemberWithValue("DT_FLAGS_1", ELF_DT_FLAGS_1); dynTagEnumBuilder.AddMemberWithValue("DT_VERDEF", ELF_DT_VERDEF); dynTagEnumBuilder.AddMemberWithValue("DT_VERDEFNUM", ELF_DT_VERDEFNUM); dynTagEnumBuilder.AddMemberWithValue("DT_VERNEED", ELF_DT_VERNEED); dynTagEnumBuilder.AddMemberWithValue("DT_VERNEEDNUM", ELF_DT_VERNEEDNUM); dynTagEnumBuilder.AddMemberWithValue("DT_VERSYM", ELF_DT_VERSYM); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_RLD_VERSION", ELF_DT_MIPS_RLD_VERSION); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_TIME_STAMP", ELF_DT_MIPS_TIME_STAMP); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_ICHECKSUM", ELF_DT_MIPS_ICHECKSUM); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_IVERSION", ELF_DT_MIPS_IVERSION); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_FLAGS", ELF_DT_MIPS_FLAGS); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_BASE_ADDRESS", ELF_DT_MIPS_BASE_ADDRESS); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_CONFLICT", ELF_DT_MIPS_CONFLICT); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_LIBLIST", ELF_DT_MIPS_LIBLIST); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_LOCAL_GOTNO", ELF_DT_MIPS_LOCAL_GOTNO); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_CONFLICTNO", ELF_DT_MIPS_CONFLICTNO); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_LIBLISTNO", ELF_DT_MIPS_LIBLISTNO); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_SYMTABNO", ELF_DT_MIPS_SYMTABNO); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_UNREFEXTNO", ELF_DT_MIPS_UNREFEXTNO); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_GOTSYM", ELF_DT_MIPS_GOTSYM); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_HIPAGENO", ELF_DT_MIPS_HIPAGENO); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_RLD_MAP", ELF_DT_MIPS_RLD_MAP); dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_RLD_MAP_REL", ELF_DT_MIPS_RLD_MAP_REL); uint64_t entrySize = m_elf32 ? 8 : 16; Ref dynTagEnum = dynTagEnumBuilder.Finalize(); Ref dynTagEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), dynTagEnum, entrySize / 2, false); const string dynTagEnumName = "e_dyn_tag"; const string dynTagEnumId = Type::GenerateAutoTypeId("elf", dynTagEnumName); QualifiedName elfdynTagEnumName = DefineType(dynTagEnumId, dynTagEnumName, dynTagEnumType); StructureBuilder dynamicEntryBuilder; dynamicEntryBuilder.AddMember(Type::NamedType(this, elfdynTagEnumName), "d_tag"); dynamicEntryBuilder.AddMember(Type::IntegerType(entrySize / 2, false), "d_val"); Ref dynEntryStruct = dynamicEntryBuilder.Finalize(); Ref dynEntryType = Type::StructureType(dynEntryStruct); QualifiedName dynEntryName = m_elf32 ? string("Elf32_Dyn"): string("Elf64_Dyn"); const string dynEntryTypeId = Type::GenerateAutoTypeId("elf", dynEntryName); QualifiedName dynEntryTypeName = DefineType(dynEntryTypeId, dynEntryName, dynEntryType); uint64_t adjustedVirtualAddr = m_dynamicTable.virtualAddress + imageBaseAdjustment; DefineDataVariable(adjustedVirtualAddr, Type::ArrayType(Type::NamedType(this, dynEntryTypeName), m_numDynamicTableEntries)); DefineAutoSymbol(new Symbol(DataSymbol, "__elf_dynamic_table", adjustedVirtualAddr, NoBinding)); } if (m_auxSymbolTable.size || m_symbolTableSection.offset) { StructureBuilder symTableBuilder; if (m_elf32) { symTableBuilder.AddMember(Type::IntegerType(4, false), "st_name"); symTableBuilder.AddMember(Type::IntegerType(4, false), "st_value"); symTableBuilder.AddMember(Type::IntegerType(4, false), "st_size"); symTableBuilder.AddMember(Type::IntegerType(1, false), "st_info"); symTableBuilder.AddMember(Type::IntegerType(1, false), "st_other"); symTableBuilder.AddMember(Type::IntegerType(2, false), "st_shndx"); } else { symTableBuilder.AddMember(Type::IntegerType(4, false), "st_name"); symTableBuilder.AddMember(Type::IntegerType(1, false), "st_info"); symTableBuilder.AddMember(Type::IntegerType(1, false), "st_other"); symTableBuilder.AddMember(Type::IntegerType(2, false), "st_shndx"); symTableBuilder.AddMember(Type::IntegerType(8, false), "st_value"); symTableBuilder.AddMember(Type::IntegerType(8, false), "st_size"); } Ref symTableStruct = symTableBuilder.Finalize(); Ref symTableType = Type::StructureType(symTableStruct); QualifiedName symTableName = m_elf32 ? string("Elf32_Sym") : string("Elf64_Sym"); const string symTableTypeId = Type::GenerateAutoTypeId("elf", symTableName); // Add types for the dynamic symbol table if (m_auxSymbolTable.size) { auto defineAuxSymTableForView = [&](Ref view) { QualifiedName symTableTypeName = view->DefineType(symTableTypeId, symTableName, symTableType); view->DefineDataVariable(m_auxSymbolTable.offset, Type::ArrayType(Type::NamedType(this, symTableTypeName), m_auxSymbolTable.size / m_auxSymbolTableEntrySize)); view->DefineAutoSymbol(new Symbol(DataSymbol, "__elf_symbol_table", m_auxSymbolTable.offset, NoBinding)); }; defineAuxSymTableForView(this); defineAuxSymTableForView(GetParentView()); } if (m_symbolTableSection.offset) { QualifiedName symTableTypeName = GetParentView()->DefineType(symTableTypeId, symTableName, symTableType); GetParentView()->DefineDataVariable(m_symbolTableSection.offset, Type::ArrayType(Type::NamedType(this, symTableTypeName), m_symbolTableSection.size / m_auxSymbolTableEntrySize)); GetParentView()->DefineAutoSymbol(new Symbol(DataSymbol, "__elf_symbol_table", m_symbolTableSection.offset, NoBinding)); } } if (m_relocSection.size && m_relocSection.entrySize > 0) { StructureBuilder relocationTableBuilder; if (m_elf32) { relocationTableBuilder.AddMember(Type::IntegerType(4, false), "r_offset"); relocationTableBuilder.AddMember(Type::IntegerType(4, false), "r_info"); } else { relocationTableBuilder.AddMember(Type::IntegerType(8, false), "r_offset"); relocationTableBuilder.AddMember(Type::IntegerType(8, false), "r_info"); }; Ref relocationTableStruct = relocationTableBuilder.Finalize(); Ref relocationTableType = Type::StructureType(relocationTableStruct); QualifiedName relocationTableName = m_elf32 ? string("Elf32_Rel") : string("Elf64_Rel"); const string relocationTableTypeId = Type::GenerateAutoTypeId("elf", relocationTableName); QualifiedName relocTableTypeName = DefineType(relocationTableTypeId, relocationTableName, relocationTableType); DefineDataVariable(m_relocSection.offset, Type::ArrayType(Type::NamedType(this, relocTableTypeName), m_relocSection.size / m_relocSection.entrySize)); DefineAutoSymbol(new Symbol(DataSymbol, "__elf_rel_table", m_relocSection.offset, NoBinding)); } if (m_relocaSection.size && m_relocaSection.entrySize > 0) { StructureBuilder relocationATableBuilder; if (m_elf32) { relocationATableBuilder.AddMember(Type::IntegerType(4, false), "r_offset"); relocationATableBuilder.AddMember(Type::IntegerType(4, false), "r_info"); relocationATableBuilder.AddMember(Type::IntegerType(4, true), "r_addend"); } else { relocationATableBuilder.AddMember(Type::IntegerType(8, false), "r_offset"); relocationATableBuilder.AddMember(Type::IntegerType(8, false), "r_info"); relocationATableBuilder.AddMember(Type::IntegerType(8, true), "r_addend"); }; Ref relocationATableStruct = relocationATableBuilder.Finalize(); Ref relocationATableType = Type::StructureType(relocationATableStruct); QualifiedName relocationATableName = m_elf32 ? string("Elf32_Rela") : string("Elf64_Rela"); const string relocationATableTypeId = Type::GenerateAutoTypeId("elf", relocationATableName); QualifiedName relocaTableTypeName = DefineType(relocationATableTypeId, relocationATableName, relocationATableType); DefineDataVariable(m_relocaSection.offset, Type::ArrayType( Type::NamedType(this, relocaTableTypeName), m_relocaSection.size / m_relocaSection.entrySize)); DefineAutoSymbol(new Symbol(DataSymbol, "__elf_rela_table", m_relocaSection.offset, NoBinding)); } // Create resolver symbol for MIPS load files containing a global offset table if (gotStart && (m_arch->GetName().find("mips") != std::string::npos)) { const char *name = "RTL_Resolve"; /* create symbol for RTL_Resolve(), address will be auto-assigned after placement in .extern */ Ref symbol = new Symbol( ExternalSymbol, /* type */ name, /* shortName */ name, /* fullName */ name, /* rawName */ 0, /* byAddr */ GlobalBinding, /* binding */ GetExternalNameSpace() /* namespace */ ); /* create type, associate it with RTL_Resolve */ Confidence> ptr_type = Type::PointerType(m_arch, Type::VoidType())->WithConfidence(BN_FULL_CONFIDENCE); Ref cc = m_arch->GetCallingConventionByName("linux-rtlresolve"); Ref type = Type::FunctionType( Type::VoidType(), /* returnValue */ cc, /* callingConvention */ { /* params */ FunctionParameter("caller_ret_addr", ptr_type), FunctionParameter("sym_idx", Type::IntegerType(4, true)), }, false, /* hasVariableArguments */ false, /* canReturn */ 0 ); /* This BinaryView helper does: 1) DefineAutoSymbol(symbol); 2) m_externalTypes[name] = type; ...so that upon BinaryView finalization, data variables are made. */ DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), symbol, type); /* Create relocation entry associated with this symbol so that reloc servicing will overwrite GOT[0] with symbol's address. */ BNRelocationInfo relocInfo; memset(&relocInfo, 0, sizeof(BNRelocationInfo)); relocInfo.base = gotStart; relocInfo.address = gotStart; relocInfo.size = m_addressSize; relocInfo.nativeType = m_addressSize == 4 ? 2 /* R_MIPS_32 */ : 18 /* R_MIPS_64 */; DefineRelocation(m_arch, relocInfo, symbol, relocInfo.address); } // Add type, data variables for TLS entries size_t tlsModuleEntrySize = 4; if (m_arch && (m_arch->GetAddressSize() == 8)) tlsModuleEntrySize = 8; for (auto offset : tlsModuleStarts) { /* All module ID's are set to 0. */ DefineDataVariable(offset, Type::IntegerType(tlsModuleEntrySize, false)->WithConfidence(BN_FULL_CONFIDENCE)); } for (auto offset : tlsOffsets) { /* In runtime reality, these become the offsets of the variables within TLS data structures. In static listing, we place a pointer to the variable for user convenience. */ DefineDataVariable(offset, Type::PointerType(m_arch, Type::VoidType())); } std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now(); double t = std::chrono::duration_cast(endTime - startTime).count() / 1000.0; m_logger->LogInfo("ELF parsing took %.3f seconds\n", t); m_stringTableCache.clear(); return true; } void ElfView::DefineElfSymbol(BNSymbolType type, const string& incomingName, uint64_t addr, bool gotEntry, BNSymbolBinding binding, size_t size, const Confidence>& typeObj) { // Ensure symbol is within the executable if (type != ExternalSymbol && !IsValidOffset(addr)) return; string name = incomingName; Confidence> symbolTypeRef; if ((type == ExternalSymbol) || (type == ImportAddressSymbol) || (type == ImportedDataSymbol)) { QualifiedName n(name); Ref lib = nullptr; symbolTypeRef = ImportTypeLibraryObject(lib, n); if (symbolTypeRef.GetValue()) { m_logger->LogDebug("elf: type Library '%s' found hit for '%s'", lib->GetName().c_str(), name.c_str()); if (type != ExternalSymbol || addr != 0) { RecordImportedObjectLibrary(GetDefaultPlatform(), addr, lib, n); } } } auto pos = name.rfind("@@"); if (type == ExternalSymbol && pos != string::npos) { name = name.substr(0, pos); } pos = name.rfind("@GLIBC"); if (type == ExternalSymbol && pos != string::npos) { name = name.substr(0, pos); } pos = name.rfind("@CXXABI"); if (type == ExternalSymbol && pos != string::npos) { name = name.substr(0, pos); } // Deprioritize local label symbol names if (type == DataSymbol && binding == LocalBinding && !name.empty() && name[0] == '.') { type = LocalLabelSymbol; } // If name is empty, symbol is not valid if (name.size() == 0) return; if (!symbolTypeRef) symbolTypeRef = typeObj; if (gotEntry) m_gotEntryLocations.emplace(addr); auto process = [=, this]() { NameSpace nameSpace = GetInternalNameSpace(); if (type == ExternalSymbol) { nameSpace = GetExternalNameSpace(); } // If name does not start with alphabetic character or symbol, prepend an underscore string rawName = name; if (!(((name[0] >= 'A') && (name[0] <= 'Z')) || ((name[0] >= 'a') && (name[0] <= 'z')) || (name[0] == '_') || (name[0] == '?') || (name[0] == '$') || (name[0] == '@') || (name[0] == '.'))) rawName = "_" + name; // Try to demangle any C++ symbols string shortName = rawName; string fullName = rawName; Confidence> typeRef = symbolTypeRef; if (m_arch) { QualifiedName demangledName; Ref demangledType; if (DemangleGeneric(m_arch, rawName, demangledType, demangledName, this, m_simplifyTemplates)) { shortName = demangledName.GetString(); fullName = shortName; if (demangledType) fullName += demangledType->GetStringAfterName(); if (!typeRef && m_extractMangledTypes && !GetDefaultPlatform()->GetFunctionByName(rawName)) typeRef = demangledType; } } if (!typeRef && m_arch && m_arch->GetName() == "hexagon") { // Apply platform types for statically linked Hexagon binaries typeRef = GetDefaultPlatform()->GetFunctionByName(rawName); } // If unable to extract type information, create a default type with the given size and heuristic confidence if (!typeRef && (size > 0 && size <= 8)) { typeRef = Type::IntegerType(size, false)->WithConfidence(BN_HEURISTIC_CONFIDENCE); } return std::pair, Confidence>>( new Symbol(type, shortName, fullName, rawName, addr, binding, nameSpace), typeRef); }; if (m_symbolQueue) { m_symbolQueue->Append(process, [this](Symbol* symbol, const Confidence>& type) { DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), symbol, type); }); } else { auto result = process(); DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), result.first, result.second); } } void ElfView::ApplyTypesToParentStringTable(const Elf64SectionHeader& section, const bool offset) { m_logger->LogInfo("Found string table of size %p at offset %p", section.size, section.offset); DataBuffer buffer = GetParentView()->ReadBuffer(section.offset, section.size); if (buffer.GetLength() != section.size) return; unordered_map> cachedTypes; for (size_t start_address = (offset ? 1 : 0); start_address < section.size; ++start_address) { size_t len; char ch = 0; for (len = 0; len < BN_MAX_STRING_LENGTH * 3 && start_address + len < section.size; ++len) { ch = buffer[start_address + len]; if (ch == 0) break; } if (len != 0 && ch == 0) { auto i = cachedTypes.find(len); Ref type; if (i == cachedTypes.end()) { type = Type::ArrayType(Type::IntegerType(1, true), len + 1); cachedTypes[len] = type; } else { type = i->second; } GetParentView()->DefineDataVariable(section.offset + start_address, type); } start_address += len; } } void ElfView::ApplyTypesToStringTable(const Elf64SectionHeader& section, const int64_t imageBaseAdjustment, const bool offset) { m_logger->LogInfo("Found string table of size %p at address %p", section.size, section.address); DataVariable existing_var; unordered_map> cachedTypes; for (size_t start_address = section.offset + (offset ? 1 : 0); start_address < section.offset + section.size;) { if (!GetParentView()->GetDataVariableAtAddress(start_address, existing_var) || (existing_var.address != start_address)) return; const uint64_t len = existing_var.type->GetElementCount(); auto i = cachedTypes.find(len); Ref type; if (i == cachedTypes.end()) { type = Type::ArrayType(Type::IntegerType(1, true), len); cachedTypes[len] = type; } else { type = i->second; } DefineDataVariable(start_address - section.offset + section.address + imageBaseAdjustment, type); start_address += len; } } string ElfView::ReadStringTable(BinaryReader& reader, const Elf64SectionHeader& section, uint64_t offset) { if (offset == 0 || offset > section.size) return ""; auto itr = m_stringTableCache.find(section.offset); if (itr == m_stringTableCache.end()) { reader.Seek(section.offset); std::vector dest; dest.resize(section.size); // We could be using a virtual reader so we can't rely on comparison against the parent view length - we just need to try and read if (!reader.TryRead(dest.data(), section.size)) { m_logger->LogError("Unable to read string table with section offset: 0x%" PRIx64 " size: 0x%" PRIx64, section.offset, section.size); return ""; } m_stringTableCache[section.offset] = std::move(dest); itr = m_stringTableCache.find(section.offset); } const std::vector& tableCache = itr->second; return std::string(&tableCache[offset], strlen(tableCache.data() + offset)); } // http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#FUNC-DES bool ElfView::DerefPpc64Descriptor(BinaryReader& reader, uint64_t addr, uint64_t& result) { /* must be 64-bit ELF, arch PPC64 */ if (m_elf32 || m_commonHeader.arch != EM_PPC64) return false; /* .opd section must exist */ if (!m_sectionOpd.size) return false; /* addr must be within .opd section */ if (addr < m_sectionOpd.address || addr >= m_sectionOpd.address + m_sectionOpd.size) return false; /* dereference descriptor to get function entry */ uint64_t saved = reader.GetOffset(); reader.Seek(m_sectionOpd.offset + (addr - m_sectionOpd.address)); bool read_success = reader.TryRead64(result);; reader.Seek(saved); return read_success; } void ElfView::ParseMiniDebugInfo() { Ref
gnuDebugdata = GetParentView()->GetSectionByName(".gnu_debugdata"); if (!gnuDebugdata) return; BinaryReader debugdataReader(GetParentView()); debugdataReader.Seek(gnuDebugdata->GetStart()); DataBuffer compressedDebug = debugdataReader.Read(gnuDebugdata->GetLength()); DataBuffer debugElf; if (!compressedDebug.XzDecompress(debugElf)) { m_logger->LogError("Invalid .gnu_debugdata contents: Failed to decompress"); return; } // Load debug bv at same address as this bv string debugBvOptions = fmt::format("{{\"loader.imageBase\": {}, \"analysis.outlining.builtins\": false, \"analysis.functions.allowUnbackedMemory\": true}}", GetStart()); Ref debugBv = Load(debugElf, false, debugBvOptions); if (!debugBv) { m_logger->LogError("Invalid .gnu_debugdata contents: Failed to create BinaryView"); return; } for (const auto& symbol : debugBv->GetSymbols()) { uint64_t addr = symbol->GetAddress(); auto symbolType = symbol->GetType(); if ((symbolType == FunctionSymbol) || (symbolType == ImportedFunctionSymbol) || (symbolType == LibraryFunctionSymbol)) { if (auto funcs = debugBv->GetAnalysisFunctionsForAddress(addr); !funcs.empty()) { const auto& archName = funcs[0]->GetArchitecture()->GetName(); if ((archName == "thumb2") || (archName == "thumb2eb")) addr |= 1; } } DefineElfSymbol( symbol->GetType(), symbol->GetRawName(), addr, false, symbol->GetBinding() ); } debugBv->GetFile()->Close(); } vector ElfView::ParseSymbolTable(BinaryReader& reader, const Elf64SectionHeader& symbolSection, const Elf64SectionHeader& stringSection, bool dynamic, size_t startEntry) { size_t size = (size_t)symbolSection.size / (m_elf32 ? 16 : 24); vector result; for (size_t i = startEntry; i < size; i++) { ElfSymbolTableEntry entry; if (!ParseSymbolTableEntry(reader, entry, i, symbolSection, stringSection, dynamic)) break; /* TODO: PPC64 specific symbol handling to be moved to architecture extension for ELF */ if (m_commonHeader.arch == EM_PPC64 && entry.type == ELF_STT_FUNC) { uint64_t func_start; if (DerefPpc64Descriptor(reader, entry.value, func_start)) { if (entry.name[0] != '.') { /* new symbol with function entry as address */ ElfSymbolTableEntry entry2 = entry; entry2.name = "." + entry2.name; entry2.value = func_start; result.push_back(entry2); m_logger->LogDebug("PPC64 symbol %s=%016x to %s=%016x\n", entry.name.c_str(), entry.value, entry2.name.c_str(), entry2.value); /* force the descriptor to a data symbol */ entry.type = ELF_STT_OBJECT; } } } result.push_back(entry); } return result; } uint64_t ElfView::PerformGetEntryPoint() const { return m_entryPoint; } BNEndianness ElfView::PerformGetDefaultEndianness() const { return m_endian; } bool ElfView::PerformIsRelocatable() const { return m_relocatable; } size_t ElfView::PerformGetAddressSize() const { return m_addressSize; } ElfViewType::ElfViewType(): BinaryViewType("ELF", "ELF") { m_logger = LogRegistry::CreateLogger("BinaryView.ElfViewType"); } Ref ElfViewType::Create(BinaryView* data) { try { return new ElfView(data); } catch (std::exception& e) { m_logger->LogErrorForException( e, "%s failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } Ref ElfViewType::Parse(BinaryView* data) { try { return new ElfView(data, true); } catch (std::exception& e) { m_logger->LogErrorForException( e, "%s failed to create view! '%s'", GetName().c_str(), e.what()); return nullptr; } } bool ElfViewType::IsTypeValidForData(BinaryView* data) { DataBuffer sig = data->ReadBuffer(0, 4); if (sig.GetLength() != 4) return false; if (memcmp(sig.GetData(), "\x7f" "ELF", 4) == 0) return true; // Cyber Grand Challenge DECREE executables can be parsed as ELF if (memcmp(sig.GetData(), "\x7f" "CGC", 4) == 0) return true; return false; } uint64_t ElfView::ParseHeaders(BinaryView* data, ElfIdent& ident, ElfCommonHeader& commonHeader, Elf64Header& header, Ref* arch, Ref* plat, string& errorMsg, BNEndianness& endianness) { if (!g_elfViewType->IsTypeValidForData(data)) { errorMsg = "invalid signature"; return 0; } // parse ElfIdent if (data->Read(&ident, 0, sizeof(ident)) != sizeof(ident)) { errorMsg = "unable to read header"; return 0; } BinaryReader reader(data); // Determine endianness from header encoding BNEndianness headerEndianness; if (ident.encoding <= 1) headerEndianness = LittleEndian; else if (ident.encoding == 2) headerEndianness = BigEndian; else { errorMsg = "invalid encoding"; return 0; } // Use header endianness by default endianness = headerEndianness; // Check for automatic x86 endianness override bool overrideX86Endianness = Settings::Instance()->Get("files.elf.overrideX86Endianness"); if (overrideX86Endianness) { // Peek at e_machine field (2 bytes at offset 0x12) with little-endian interpretation uint8_t machineBytes[2]; if (data->Read(machineBytes, 0x12, 2) == 2) { uint16_t machineLE = machineBytes[0] | (machineBytes[1] << 8); if (machineLE == EM_386 || machineLE == EM_X86_64) { endianness = LittleEndian; if (endianness != headerEndianness) { m_logger->LogWarn("ELF endianness automatically overridden to little-endian for x86/x86_64 (header specified %s)", headerEndianness == LittleEndian ? "little-endian" : "big-endian"); } } } } // Log detected endianness if no override occurred if (endianness == headerEndianness) { m_logger->LogInfo("Detected %s ELF", endianness == LittleEndian ? "little-endian" : "big-endian"); } // parse ElfCommonHeader reader.SetEndianness(endianness); reader.Seek(sizeof(ident)); commonHeader.type = reader.Read16(); commonHeader.arch = reader.Read16(); commonHeader.version = reader.Read32(); bool is32bit = ident.fileClass == 1; // parse Elf64Header if (ident.fileClass == 1) // 32-bit ELF { header.entry = reader.Read32(); header.programHeaderOffset = reader.Read32(); header.sectionHeaderOffset = reader.Read32(); header.flags = reader.Read32(); header.headerSize = reader.Read16(); header.programHeaderSize = reader.Read16(); header.programHeaderCount = reader.Read16(); header.sectionHeaderSize = reader.Read16(); header.sectionHeaderCount = reader.Read16(); header.stringTable = reader.Read16(); } else if (ident.fileClass == 2) // 64-bit ELF { header.entry = reader.Read64(); header.programHeaderOffset = reader.Read64(); header.sectionHeaderOffset = reader.Read64(); header.flags = reader.Read32(); header.headerSize = reader.Read16(); header.programHeaderSize = reader.Read16(); header.programHeaderCount = reader.Read16(); header.sectionHeaderSize = reader.Read16(); header.sectionHeaderCount = reader.Read16(); header.stringTable = reader.Read16(); } else { errorMsg = "invalid file class"; return 0; } // This is some disgusting code duplication, the PowerPC ELF recognizer // needs some section information passed to it: // (1) contents of the .ppc.EMB.apuinfo to figure out additional // processor information (SPE, Altivec, etc.) // (2) whether any sections have VLE flags // // But this function doesn't have a handle to the ElfView, so we // duplicate the section iteration/parsing logic // // We're early enough in the process that if sizes aren't what we expect // them to be, we just don't pass section info to the ELF recognizer // function, but pass everything else to aid troubleshooting uint16_t sectionHeaderSize = header.sectionHeaderSize; uint32_t sectionCount = header.sectionHeaderCount; if (is32bit && (sectionHeaderSize != sizeof(Elf32SectionHeader))) { m_logger->LogWarn( "The section header size reported by e_shentsize (0x%lx) is different from the size of Elf32_Shdr (0x%lx). " "Won't do first pass section header parsing.", sectionHeaderSize, sizeof(Elf32SectionHeader)); sectionCount = 0; } else if (!is32bit && (sectionHeaderSize != sizeof(Elf64SectionHeader))) { m_logger->LogWarn( "The section header size reported by e_shentsize (0x%lx) is different from the size of Elf64_Shdr (0x%lx). " "Won't do first pass section header parsing.", sectionHeaderSize, sizeof(Elf64SectionHeader)); sectionCount = 0; } map> metadataMap = { {"EI_CLASS", new Metadata((uint64_t) ident.fileClass)}, {"EI_DATA", new Metadata((uint64_t) ident.encoding)}, {"EI_OSABI", new Metadata((uint64_t) ident.os)}, {"e_type", new Metadata((uint64_t) commonHeader.type)}, {"e_machine", new Metadata((uint64_t) commonHeader.arch)}, {"e_flags", new Metadata((uint64_t) header.flags)}, }; BinaryReader sectionReader(data); sectionReader.SetEndianness(endianness); uint64_t flagsOffset = header.sectionHeaderOffset; if (is32bit) flagsOffset += offsetof(Elf32SectionHeader, flags); else flagsOffset += offsetof(Elf64SectionHeader, flags); for (unsigned int i=0; i < sectionCount; ++i) { sectionReader.Seek(flagsOffset); uint64_t flags; try { if (is32bit) flags = sectionReader.Read32(); else flags = sectionReader.Read64(); } catch (ReadException&) { m_logger->LogWarn("Failed to read section flags at offset %" PRIx64, flagsOffset); // Note that any previously read flags values will // still persist in the metadata map sectionCount = 0; break; } char metaname[0x20]; snprintf(metaname, sizeof metaname, "sectionFlags[%d]", i); metadataMap[metaname] = new Metadata((uint64_t)flags); flagsOffset += header.sectionHeaderSize; } metadataMap["numSections"] = new Metadata((uint64_t) sectionCount); Ref metadata = new Metadata(metadataMap); // retrieve architecture // FIXME: Architecture registration methods should perhaps be virtual and take the raw data, or some additional opaque information. bool checkForARMBE8 = Settings::Instance()->Get("files.elf.detectARMBE8Binary"); if (checkForARMBE8) endianness = ((commonHeader.arch == EM_ARM) && (header.flags & EF_ARM_BE8)) ? BigEndian : endianness; /* for architectures where .e_machine field doesn't disambiguate between 32/64 (like MIPS), form the conventional alternative id, including the .e_ident[EI_CLASS] field */ uint32_t altArchId = (ident.fileClass << 16) | commonHeader.arch; Ref recognizedPlatform = g_elfViewType->RecognizePlatform(commonHeader.arch, endianness, data, metadata); if (!recognizedPlatform) { /* second try with the alternative architecture identifier */ recognizedPlatform = g_elfViewType->RecognizePlatform(altArchId, endianness, data, metadata); } if (recognizedPlatform) { if (plat) *plat = recognizedPlatform; if (arch) *arch = recognizedPlatform->GetArchitecture(); } else { BNEndianness codeEndianness = endianness; if (checkForARMBE8 && (commonHeader.arch == EM_ARM) && (header.flags & EF_ARM_BE8)) codeEndianness = LittleEndian; if (arch) { *arch = g_elfViewType->GetArchitecture(commonHeader.arch, codeEndianness); if (!*arch) { /* second try with the alternative architecture identifier */ *arch = g_elfViewType->GetArchitecture(altArchId, codeEndianness); } } } return reader.GetOffset(); } Ref ElfViewType::GetLoadSettingsForData(BinaryView* data) { Ref viewRef = Parse(data); if (!viewRef || !viewRef->Init()) { m_logger->LogWarn("Failed to initialize view of type '%s'. Generating default load settings.", GetName().c_str()); viewRef = data; } Ref settings = GetDefaultLoadSettingsForData(viewRef); // specify default load settings that can be overridden vector overrides = {"loader.imageBase", "loader.platform"}; if (!viewRef->IsRelocatable()) settings->UpdateProperty("loader.imageBase", "message", "Note: File indicates image is not relocatable."); for (const auto& override : overrides) { if (settings->Contains(override)) settings->UpdateProperty(override, "readOnly", false); } return settings; } extern "C" { BN_DECLARE_CORE_ABI_VERSION #ifdef DEMO_EDITION bool ElfPluginInit() #else BINARYNINJAPLUGIN bool CorePluginInit() #endif { InitElfViewType(); return true; } }