From 6be23f64a288b0d539e921fbf7e5921f04cbd36f Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Thu, 22 Sep 2022 14:09:33 -0400 Subject: [PATCH] GP-2577 fix problem handling Elf32 missing sections / headers The special flag for offset values (-1) wasn't being recognized in 32bit binaries, causing the ELF loader to try to read from index 4294967295, causing an exception: java.io.IOException: Invalid index: 4294967295 --- .../cmd/formats/ElfBinaryAnalysisCommand.java | 6 +-- .../app/util/bin/format/elf/ElfConstants.java | 5 +++ .../format/elf/ElfDefaultGotPltMarkup.java | 2 +- .../app/util/bin/format/elf/ElfHeader.java | 12 +++--- .../util/bin/format/elf/ElfProgramHeader.java | 12 +++++- .../util/bin/format/elf/ElfSectionHeader.java | 17 ++++++-- .../app/util/opinion/ElfProgramBuilder.java | 41 ++++++++----------- 7 files changed, 57 insertions(+), 38 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/formats/ElfBinaryAnalysisCommand.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/formats/ElfBinaryAnalysisCommand.java index 8e88d655d0..2bb23a25c3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/formats/ElfBinaryAnalysisCommand.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/formats/ElfBinaryAnalysisCommand.java @@ -188,10 +188,8 @@ public class ElfBinaryAnalysisCommand extends FlatProgramAPI cu.setComment(CodeUnit.PLATE_COMMENT, "#" + i + ") " + name + " at 0x" + Long.toHexString(sections[i].getAddress())); - if (sections[i].getSize() == 0) { - continue; - } - if (sections[i].getType() == ElfSectionHeaderConstants.SHT_NOBITS) { + if (sections[i].getType() == ElfSectionHeaderConstants.SHT_NOBITS || + sections[i].getSize() == 0 || sections[i].isInvalidOffset()) { continue; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfConstants.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfConstants.java index a78be26c37..763b136bf1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfConstants.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfConstants.java @@ -518,4 +518,9 @@ public interface ElfConstants { */ public static final short PN_XNUM = (short) 0xffff; + /** + * 32bit "-1", used in 32bit files to signal an invalid offset + */ + public static final long ELF32_INVALID_OFFSET = 0xFFFFFFFFL; + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java index baed2f3c30..5225f5502e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java @@ -143,7 +143,7 @@ public class ElfDefaultGotPltMarkup { ElfProgramHeader relocTableLoadHeader = elf.getProgramLoadHeaderContaining(relocTableAddr); - if (relocTableLoadHeader == null || relocTableLoadHeader.getOffset() < 0) { + if (relocTableLoadHeader == null || relocTableLoadHeader.isInvalidOffset()) { return; } long relocTableOffset = relocTableLoadHeader.getOffset(relocTableAddr); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java index 26cb7ab791..460cd53d39 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java @@ -532,7 +532,7 @@ public class ElfHeader implements StructConverter, Writeable { " linked to symbol table section " + symbolTableSection.getNameAsString() + " affecting " + relocaBaseName); - if (section.getOffset() < 0) { + if (section.isInvalidOffset()) { return; } @@ -614,7 +614,7 @@ public class ElfHeader implements StructConverter, Writeable { Long.toHexString(relocTableAddr)); return; } - if (relocTableLoadHeader.getOffset() < 0) { + if (relocTableLoadHeader.isInvalidOffset()) { return; } @@ -881,7 +881,7 @@ public class ElfHeader implements StructConverter, Writeable { for (ElfSectionHeader symbolTableSectionHeader : sectionHeaders) { if (symbolTableSectionHeader.getType() == ElfSectionHeaderConstants.SHT_SYMTAB || symbolTableSectionHeader.getType() == ElfSectionHeaderConstants.SHT_DYNSYM) { - if (symbolTableSectionHeader.getOffset() < 0) { + if (symbolTableSectionHeader.isInvalidOffset()) { continue; } @@ -1621,7 +1621,8 @@ public class ElfHeader implements StructConverter, Writeable { long fileRangeLength) { long maxOffset = fileOffset + fileRangeLength - 1; for (ElfSectionHeader section : sectionHeaders) { - if (section.getType() == ElfSectionHeaderConstants.SHT_NULL) { + if (section.getType() == ElfSectionHeaderConstants.SHT_NULL || + section.isInvalidOffset()) { continue; } long size = section.getSize(); @@ -1748,7 +1749,8 @@ public class ElfHeader implements StructConverter, Writeable { public ElfProgramHeader getProgramLoadHeaderContainingFileOffset(long offset) { for (ElfProgramHeader programHeader : programHeaders) { if (programHeader == null || - programHeader.getType() != ElfProgramHeaderConstants.PT_LOAD) { + programHeader.getType() != ElfProgramHeaderConstants.PT_LOAD || + programHeader.isInvalidOffset()) { continue; } long start = programHeader.getOffset(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfProgramHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfProgramHeader.java index 709e6531a7..58060255a0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfProgramHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfProgramHeader.java @@ -15,9 +15,10 @@ */ package ghidra.app.util.bin.format.elf; +import java.util.HashMap; + import java.io.IOException; import java.io.RandomAccessFile; -import java.util.HashMap; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.StructConverter; @@ -315,6 +316,15 @@ public class ElfProgramHeader return p_offset; } + /** + * Return true if this program header's offset is invalid. + * + * @return true if this program header's offset is invalid + */ + public boolean isInvalidOffset() { + return p_offset < 0 || (header.is32Bit() && p_offset == ElfConstants.ELF32_INVALID_OFFSET); + } + /** * Compute the file offset associated with the specified loaded virtual address * defined by this PT_LOAD program header. This can be useful when attempting to locate diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSectionHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSectionHeader.java index 572db5afcf..1c92949ca6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSectionHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfSectionHeader.java @@ -15,9 +15,10 @@ */ package ghidra.app.util.bin.format.elf; -import java.io.*; import java.util.HashMap; +import java.io.*; + import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.format.MemoryLoadable; @@ -338,8 +339,8 @@ public class ElfSectionHeader implements StructConverter, Writeable, MemoryLoada try { if (sh_name >= 0 && e_shstrndx > 0 && e_shstrndx < sections.length) { // read section name from string table - long stringTableOffset = sections[e_shstrndx].getOffset(); - if (stringTableOffset >= 0) { + if (!sections[e_shstrndx].isInvalidOffset()) { + long stringTableOffset = sections[e_shstrndx].getOffset(); long offset = stringTableOffset + sh_name; if (offset < reader.length()) { name = reader.readAsciiString(stringTableOffset + sh_name); @@ -396,6 +397,16 @@ public class ElfSectionHeader implements StructConverter, Writeable, MemoryLoada return sh_offset; } + /** + * Returns true if this section header's offset is invalid. + * + * @return true if this section header's offset is invalid + */ + public boolean isInvalidOffset() { + return sh_offset < 0 || + (header.is32Bit() && sh_offset == ElfConstants.ELF32_INVALID_OFFSET); + } + /** * Sets the section's size. * @param size the new size of the section diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java index 69d86e5bb6..7ea1f870f1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java @@ -15,11 +15,12 @@ */ package ghidra.app.util.opinion; +import java.util.*; + import java.io.*; import java.math.BigInteger; import java.nio.file.AccessMode; import java.text.NumberFormat; -import java.util.*; import org.apache.commons.compress.compressors.xz.XZCompressorInputStream; import org.apache.commons.lang3.StringUtils; @@ -224,30 +225,26 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { for (ElfProgramHeader segment : segments) { monitor.checkCanceled(); monitor.incrementProgress(1); - if (segment.getType() == ElfProgramHeaderConstants.PT_NULL) { + long size = segment.getFileSize(); + if (segment.getType() == ElfProgramHeaderConstants.PT_NULL || + segment.isInvalidOffset() || size <= 0) { continue; } - long size = segment.getFileSize(); long offset = segment.getOffset(); - if (size > 0) { - fileMap.paintRange(offset, offset + size - 1, -2); // -2: used by segment - } + fileMap.paintRange(offset, offset + size - 1, -2); // -2: used by segment } for (ElfSectionHeader section : sections) { monitor.checkCanceled(); monitor.incrementProgress(1); + long size = section.getSize(); if (section.getType() == ElfSectionHeaderConstants.SHT_NULL || - section.getType() == ElfSectionHeaderConstants.SHT_NOBITS) { + section.getType() == ElfSectionHeaderConstants.SHT_NOBITS || + section.isInvalidOffset() || size <= 0) { continue; } - section.getSize(); - section.getOffset(); - long size = section.getSize(); long offset = section.getOffset(); - if (size > 0) { - fileMap.paintRange(offset, offset + size - 1, -3); // -3: used by section - } + fileMap.paintRange(offset, offset + size - 1, -3); // -3: used by section } // Ignore header regions which will always be allocated to blocks @@ -2769,13 +2766,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { // Locate possible load of Elf header within section (i.e., start of file) Address headerAddr = null; for (ElfSectionHeader section : elf.getSections()) { - if (section.getType() == ElfSectionHeaderConstants.SHT_NOBITS) { + if (section.getType() == ElfSectionHeaderConstants.SHT_NOBITS || + section.isInvalidOffset()) { continue; } long startOffset = section.getOffset(); - if (startOffset < 0) { - continue; - } long endOffset = startOffset + section.getSize() - 1; if (fileOffset >= startOffset && headerEndOffset <= endOffset) { headerAddr = findLoadAddress(section, fileOffset - section.getOffset()); @@ -2787,13 +2782,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { // Locate possible load of Elf header within segment for (ElfProgramHeader segment : elf.getProgramHeaders()) { - if (segment.getType() == ElfProgramHeaderConstants.PT_NULL) { + if (segment.getType() == ElfProgramHeaderConstants.PT_NULL || + segment.isInvalidOffset()) { continue; } long startOffset = segment.getOffset(); - if (startOffset < 0) { - continue; - } long endOffset = startOffset + segment.getFileSize() - 1; if (fileOffset >= startOffset && headerEndOffset <= endOffset) { headerAddr = findLoadAddress(segment, fileOffset - segment.getOffset()); @@ -2948,7 +2941,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { if (!includeOtherBlocks) { continue; } - if (fileOffset < 0 || fileOffset >= fileBytes.getSize()) { + if (elfProgramHeader.isInvalidOffset() || fileOffset >= fileBytes.getSize()) { log("Skipping segment[" + i + ", " + elfProgramHeader.getDescription() + "] with invalid file offset"); continue; @@ -2964,7 +2957,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { continue; } } - if (fileOffset < 0 || fileOffset >= fileBytes.getSize()) { + if (elfProgramHeader.isInvalidOffset() || fileOffset >= fileBytes.getSize()) { log("Skipping PT_LOAD segment[" + i + ", " + elfProgramHeader.getDescription() + "] with invalid file offset"); continue; @@ -3168,7 +3161,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { (includeOtherBlocks || elfSectionToLoad.isAlloc())) { long fileOffset = elfSectionToLoad.getOffset(); if (type != ElfSectionHeaderConstants.SHT_NOBITS && - (fileOffset < 0 || fileOffset >= fileBytes.getSize())) { + (elfSectionToLoad.isInvalidOffset() || fileOffset >= fileBytes.getSize())) { log("Skipping section [" + elfSectionToLoad.getNameAsString() + "] with invalid file offset 0x" + Long.toHexString(fileOffset)); continue;