GP-3620 Complete changes to eliminate mutability of ELF related headers

intended for import/loading only.
This commit is contained in:
ghidra1 2023-04-19 15:55:44 -04:00
parent 28cc3af5e0
commit 8fb5a88b89
12 changed files with 355 additions and 542 deletions

View file

@ -292,7 +292,7 @@ public class BinaryReader {
* For example, if current index was 123 and align value was 16, then current index would * For example, if current index was 123 and align value was 16, then current index would
* be advanced to 128. * be advanced to 128.
* *
* @param alignValue * @param alignValue position index alignment
* @return the number of bytes required to align (0..alignValue-1) * @return the number of bytes required to align (0..alignValue-1)
*/ */
public int align(int alignValue) { public int align(int alignValue) {
@ -305,9 +305,11 @@ public class BinaryReader {
* A convenience method for setting the index using a 32 bit integer. * A convenience method for setting the index using a 32 bit integer.
* *
* @param index new index, treated as a 32 bit unsigned integer * @param index new index, treated as a 32 bit unsigned integer
* @return previous reader offset for use with {@link #setPointerIndex(long)} to restore
* previous position.
*/ */
public void setPointerIndex(int index) { public long setPointerIndex(int index) {
this.currentIndex = Integer.toUnsignedLong(index); return setPointerIndex(Integer.toUnsignedLong(index));
} }
/** /**
@ -316,9 +318,12 @@ public class BinaryReader {
* to operate as a pseudo-iterator. * to operate as a pseudo-iterator.
* *
* @param index the byte provider index value * @param index the byte provider index value
* @return previous reader offset for use with this method to restore previous position.
*/ */
public void setPointerIndex(long index) { public long setPointerIndex(long index) {
this.currentIndex = index; long oldIndex = currentIndex;
currentIndex = index;
return oldIndex;
} }
/** /**

View file

@ -52,79 +52,85 @@ import ghidra.util.StringUtilities;
*/ */
public class ElfDynamic { public class ElfDynamic {
private ElfHeader elf; private final ElfHeader elf;
private int d_tag; private final int d_tag;
private long d_val; private final long d_val;
public ElfDynamic(BinaryReader reader, ElfHeader elf) /**
throws IOException { * Construct an ELF dynamic table entry
* @param reader to read dynamic entry at current position
* (reader is not retained, position moves to next entry)
* @param elf ELF header
* @throws IOException if an IO error occurs during parse
*/
public ElfDynamic(BinaryReader reader, ElfHeader elf) throws IOException {
this.elf = elf; this.elf = elf;
if (elf.is32Bit()) { if (elf.is32Bit()) {
d_tag = reader.readNextInt(); d_tag = reader.readNextInt();
d_val = Integer.toUnsignedLong(reader.readNextInt()); d_val = reader.readNextUnsignedInt();
} }
else { else {
d_tag = (int) reader.readNextLong(); d_tag = (int) reader.readNextLong();
d_val = reader.readNextLong(); d_val = reader.readNextLong();
} }
} }
/** /**
* Constructs a new ELF dynamic with the specified tag and value. * Constructs a new ELF dynamic with the specified tag and value.
* @param tag the tag (or type) of this dynamic * @param tag the tag (or type) of this dynamic
* @param value the value (or pointer) of this dynamic * @param value the value (or pointer) of this dynamic
* @param elf the elf header * @param elf the elf header
*/ */
public ElfDynamic(int tag, long value, ElfHeader elf) { public ElfDynamic(int tag, long value, ElfHeader elf) {
this.d_tag = tag; this.d_tag = tag;
this.d_val = value; this.d_val = value;
this.elf = elf; this.elf = elf;
} }
/** /**
* Constructs a new ELF dynamic with the specified (enum) tag and value. * Constructs a new ELF dynamic with the specified (enum) tag and value.
* @param tag the (enum) tag (or type) of this dynamic * @param tag the (enum) tag (or type) of this dynamic
* @param value the value (or pointer) of this dynamic * @param value the value (or pointer) of this dynamic
* @param elf the elf header * @param elf the elf header
*/ */
public ElfDynamic(ElfDynamicType tag, long value, ElfHeader elf) { public ElfDynamic(ElfDynamicType tag, long value, ElfHeader elf) {
this(tag.value, value, elf); this(tag.value, value, elf);
} }
/** /**
* Returns the value that controls the interpretation of the * Returns the value that controls the interpretation of the
* the d_val and/or d_ptr. * the d_val and/or d_ptr.
* @return the tag (or type) of this dynamic * @return the tag (or type) of this dynamic
*/ */
public int getTag() { public int getTag() {
return d_tag; return d_tag;
} }
/** /**
* Returns the enum value that controls the interpretation of the * Returns the enum value that controls the interpretation of the
* the d_val and/or d_ptr (or null if unknown). * the d_val and/or d_ptr (or null if unknown).
* @return the enum tag (or type) of this dynamic or null if unknown * @return the enum tag (or type) of this dynamic or null if unknown
*/ */
public ElfDynamicType getTagType() { public ElfDynamicType getTagType() {
return elf.getDynamicType(d_tag); return elf.getDynamicType(d_tag);
} }
/** /**
* Returns the object whose integer values represent various interpretations. * Returns the object whose integer values represent various interpretations.
* For example, if d_tag == DT_SYMTAB, then d_val holds the address of the symbol table. * For example, if d_tag == DT_SYMTAB, then d_val holds the address of the symbol table.
* But, if d_tag == DT_SYMENT, then d_val holds the size of each symbol entry. * But, if d_tag == DT_SYMENT, then d_val holds the size of each symbol entry.
* @return the Elf32_Word object represent integer values with various interpretations * @return the Elf32_Word object represent integer values with various interpretations
*/ */
public long getValue() { public long getValue() {
return d_val; return d_val;
} }
/** /**
* A convenience method for getting a string representing the d_tag value. * A convenience method for getting a string representing the d_tag value.
* For example, if d_tag == DT_SYMTAB, then this method returns "DT_SYMTAB". * For example, if d_tag == DT_SYMTAB, then this method returns "DT_SYMTAB".
* @return a string representing the d_tag value * @return a string representing the d_tag value
*/ */
public String getTagAsString() { public String getTagAsString() {
ElfDynamicType tagType = getTagType(); ElfDynamicType tagType = getTagType();
if (tagType != null) { if (tagType != null) {
@ -138,12 +144,11 @@ public class ElfDynamic {
return getTagAsString(); return getTagAsString();
} }
/** /**
* @return the size in bytes of this object. * @return the size in bytes of this object.
*/ */
public int sizeof() { public int sizeof() {
return elf.is32Bit() ? 8 : 16; return elf.is32Bit() ? 8 : 16;
} }
} }

View file

@ -35,33 +35,36 @@ import ghidra.util.exception.NotFoundException;
*/ */
public class ElfDynamicTable implements ElfFileSection { public class ElfDynamicTable implements ElfFileSection {
private List<ElfDynamic> dynamics = new ArrayList<ElfDynamic>(); private final List<ElfDynamic> dynamics = new ArrayList<ElfDynamic>();
private ElfHeader header; private final ElfHeader header;
private long fileOffset; private final long fileOffset;
private long addrOffset; private final long addrOffset;
public ElfDynamicTable(BinaryReader reader, ElfHeader header, /**
long fileOffset, long addrOffset) throws IOException { * Construct an ELF Dynamic data table
* @param reader byte provider reader (reader is not retained and position is unaffected)
long oldptr = reader.getPointerIndex(); * @param header elf header
* @param fileOffset file offset which will be used to temporarily position reader
* @param addrOffset memory address offset
* @throws IOException if IO error occurs during parse
*/
public ElfDynamicTable(BinaryReader reader, ElfHeader header, long fileOffset, long addrOffset)
throws IOException {
this.header = header; this.header = header;
this.fileOffset = fileOffset; this.fileOffset = fileOffset;
this.addrOffset = addrOffset; this.addrOffset = addrOffset;
reader.setPointerIndex(fileOffset);
// Collect set of all _DYNAMIC array tags specified in .dynamic section // Collect set of all _DYNAMIC array tags specified in .dynamic section
BinaryReader entryReader = reader.clone(fileOffset);
while (true) { while (true) {
ElfDynamic dyn = new ElfDynamic(reader, header); ElfDynamic dyn = new ElfDynamic(entryReader, header);
dynamics.add(dyn); dynamics.add(dyn);
if (dyn.getTag() == ElfDynamicType.DT_NULL.value) { if (dyn.getTag() == ElfDynamicType.DT_NULL.value) {
break; break;
} }
} }
reader.setPointerIndex(oldptr);
} }
/** /**
@ -119,8 +122,7 @@ public class ElfDynamicTable implements ElfFileSection {
* @throws NotFoundException if requested value type not found * @throws NotFoundException if requested value type not found
*/ */
public long getDynamicValue(long type) throws NotFoundException { public long getDynamicValue(long type) throws NotFoundException {
for (int i = 0; i < dynamics.size(); i++) { for (ElfDynamic dyn : dynamics) {
ElfDynamic dyn = dynamics.get(i);
if (dyn.getTag() == type) { if (dyn.getTag() == type) {
return dyn.getValue(); return dyn.getValue();
} }
@ -143,8 +145,7 @@ public class ElfDynamicTable implements ElfFileSection {
* @return true if dynamic value exists * @return true if dynamic value exists
*/ */
public boolean containsDynamicValue(long type) { public boolean containsDynamicValue(long type) {
for (int i = 0; i < dynamics.size(); i++) { for (ElfDynamic dyn : dynamics) {
ElfDynamic dyn = dynamics.get(i);
if (dyn.getTag() == type) { if (dyn.getTag() == type) {
return true; return true;
} }

View file

@ -24,8 +24,6 @@ import ghidra.app.util.bin.format.elf.ElfRelocationTable.TableFormat;
import ghidra.app.util.bin.format.elf.extend.ElfExtensionFactory; import ghidra.app.util.bin.format.elf.extend.ElfExtensionFactory;
import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter; import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.exception.NotFoundException; import ghidra.util.exception.NotFoundException;
@ -44,39 +42,41 @@ public class ElfHeader implements StructConverter {
private HashMap<Integer, ElfSectionHeaderType> sectionHeaderTypeMap; private HashMap<Integer, ElfSectionHeaderType> sectionHeaderTypeMap;
private HashMap<Integer, ElfDynamicType> dynamicTypeMap; private HashMap<Integer, ElfDynamicType> dynamicTypeMap;
private ByteProvider provider; // original byte provider private final ByteProvider provider; // original byte provider
private BinaryReader reader; // unlimited reader private final BinaryReader reader; // unlimited reader
private ElfLoadAdapter elfLoadAdapter = new ElfLoadAdapter();
private byte e_ident_magic_num; //magic number
private String e_ident_magic_str; //magic string
private byte e_ident_class; //file class
private byte e_ident_data; //data encoding
@SuppressWarnings("unused") @SuppressWarnings("unused")
private byte e_ident_version; //file version private final byte e_ident_magic_num; //magic number
private byte e_ident_osabi; //operating system and abi private final String e_ident_magic_str; //magic string
private byte e_ident_abiversion; //abi version private final byte e_ident_class; //file class
private final byte e_ident_data; //data encoding
@SuppressWarnings("unused") @SuppressWarnings("unused")
private byte[] e_ident_pad; //padding private final byte e_ident_version; //file version
private short e_type; //object file type private final byte e_ident_osabi; //operating system and abi
private short e_machine; //target architecture private final byte e_ident_abiversion; //abi version
private int e_version; //object file version @SuppressWarnings("unused")
private long e_entry; //executable entry point private final byte[] e_ident_pad; //padding
private long e_phoff; //program header table offset private final short e_type; //object file type
private long e_shoff; //section header table offset private final short e_machine; //target architecture
private int e_flags; //processor-specific flags private final int e_version; //object file version
private short e_ehsize; //elf header size private final long e_entry; //executable entry point
private short e_phentsize; //size of entries in the program header table private final long e_phoff; //program header table offset
private int e_phnum; //number of enties in the program header table (may be extended and may not be preserved) private final long e_shoff; //section header table offset
private short e_shentsize; //size of entries in the section header table private final int e_flags; //processor-specific flags
private int e_shnum; //number of enties in the section header table (may be extended and may not be preserved) private final short e_ehsize; //elf header size
private int e_shstrndx; //section index of the section name string table (may be extended and may not be preserved) private final short e_phentsize; //size of entries in the program header table
private final int e_phnum; //number of enties in the program header table (may be extended and may not be preserved)
private final short e_shentsize; //size of entries in the section header table
private final int e_shnum; //number of enties in the section header table (may be extended and may not be preserved)
private final int e_shstrndx; //section index of the section name string table (may be extended and may not be preserved)
private Structure headerStructure; private Structure headerStructure;
private boolean parsed = false; private boolean parsed = false;
private boolean parsedSectionHeaders = false; private boolean parsedSectionHeaders = false;
private ElfLoadAdapter elfLoadAdapter = new ElfLoadAdapter();
private ElfSectionHeader section0 = null; private ElfSectionHeader section0 = null;
private ElfSectionHeader[] sectionHeaders = new ElfSectionHeader[0]; private ElfSectionHeader[] sectionHeaders = new ElfSectionHeader[0];
private ElfProgramHeader[] programHeaders = new ElfProgramHeader[0]; private ElfProgramHeader[] programHeaders = new ElfProgramHeader[0];
@ -108,31 +108,6 @@ public class ElfHeader implements StructConverter {
this.errorConsumer = errorConsumer != null ? errorConsumer : msg -> { this.errorConsumer = errorConsumer != null ? errorConsumer : msg -> {
/* no logging if errorConsumer was null */ /* no logging if errorConsumer was null */
}; };
initElfHeader();
}
/**
* Returns the unconstrained binary reader (i.e., reads beyond EOF
* will return 0-bytes).
* @return the binary reader
*/
public BinaryReader getReader() {
return reader;
}
/**
* Returns the byte provider
* @return the byte provider
*/
public ByteProvider getByteProvider() {
return provider;
}
void logError(String msg) {
errorConsumer.accept(msg);
}
protected void initElfHeader() throws ElfException {
try { try {
if (!Arrays.equals(ElfConstants.MAGIC_BYTES, if (!Arrays.equals(ElfConstants.MAGIC_BYTES,
@ -179,41 +154,63 @@ public class ElfHeader implements StructConverter {
e_ehsize = reader.readNextShort(); e_ehsize = reader.readNextShort();
e_phentsize = reader.readNextShort(); e_phentsize = reader.readNextShort();
e_phnum = reader.readNextUnsignedShort();
int phnum = reader.readNextUnsignedShort();
if (phnum == Short.toUnsignedInt(ElfConstants.PN_XNUM)) {
phnum = readExtendedProgramHeaderCount(); // use extended stored program header count
}
e_phnum = phnum;
e_shentsize = reader.readNextShort(); e_shentsize = reader.readNextShort();
e_shnum = reader.readNextUnsignedShort();
e_shstrndx = Short.toUnsignedInt(reader.readNextShort()); int shnum = reader.readNextUnsignedShort();
if (shnum == 0 ||
if (e_shnum == 0 || shnum >= Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_LORESERVE)) {
e_shnum >= Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_LORESERVE)) { shnum = readExtendedSectionHeaderCount(); // use extended stored section header count
e_shnum = readExtendedSectionHeaderCount(); // use extended stored section header count
}
if (e_phnum == Short.toUnsignedInt(ElfConstants.PN_XNUM)) {
e_phnum = readExtendedProgramHeaderCount(); // use extended stored program header count
} }
e_shnum = shnum;
int shstrndx = reader.readNextUnsignedShort();
if (e_shnum == 0) { if (e_shnum == 0) {
e_shstrndx = 0; shstrndx = 0;
} }
else if (e_shstrndx == Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_XINDEX)) { else if (shstrndx == Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_XINDEX)) {
e_shstrndx = readExtendedSectionHeaderStringTableIndex(); shstrndx = readExtendedSectionHeaderStringTableIndex();
} }
e_shstrndx = shstrndx;
} }
catch (IOException e) { catch (IOException e) {
throw new ElfException(e); throw new ElfException(e);
} }
} }
/**
* Returns the unconstrained binary reader (i.e., reads beyond EOF
* will return 0-bytes).
* @return the binary reader
*/
public BinaryReader getReader() {
return reader;
}
/**
* Returns the byte provider
* @return the byte provider
*/
public ByteProvider getByteProvider() {
return provider;
}
void logError(String msg) {
errorConsumer.accept(msg);
}
private ElfSectionHeader getSection0() throws IOException { private ElfSectionHeader getSection0() throws IOException {
if (section0 == null && e_shoff != 0) { if (section0 == null && e_shoff != 0) {
if (!providerContainsRegion(e_shoff, e_shentsize)) { if (!providerContainsRegion(e_shoff, e_shentsize)) {
return null; return null;
} }
reader.setPointerIndex(e_shoff); section0 = new ElfSectionHeader(reader.clone(e_shoff), this);
section0 = new ElfSectionHeader(reader, this);
} }
return section0; return section0;
} }
@ -544,18 +541,17 @@ public class ElfHeader implements StructConverter {
format = TableFormat.RELR; format = TableFormat.RELR;
} }
ElfRelocationTable relocTable = new ElfRelocationTable(reader, ElfRelocationTable relocTable =
this, section, section.getOffset(), section.getAddress(), section.getSize(), new ElfRelocationTable(reader, this, section, section.getOffset(),
section.getEntrySize(), addendTypeReloc, symbolTable, sectionToBeRelocated, section.getAddress(), section.getSize(), section.getEntrySize(),
format); addendTypeReloc, symbolTable, sectionToBeRelocated, format);
relocationTableList.add(relocTable); relocationTableList.add(relocTable);
} }
} }
catch (NotFoundException e) { catch (NotFoundException e) {
errorConsumer errorConsumer.accept("Failed to process relocation section " +
.accept("Failed to process relocation section " + section.getNameAsString() + section.getNameAsString() + ": " + e.getMessage());
": " + e.getMessage());
} }
} }
@ -607,9 +603,8 @@ public class ElfHeader implements StructConverter {
ElfProgramHeader relocTableLoadHeader = getProgramLoadHeaderContaining(relocTableAddr); ElfProgramHeader relocTableLoadHeader = getProgramLoadHeaderContaining(relocTableAddr);
if (relocTableLoadHeader == null) { if (relocTableLoadHeader == null) {
errorConsumer errorConsumer.accept("Failed to locate " + relocTableAddrType.name +
.accept("Failed to locate " + relocTableAddrType.name + " in memory at 0x" + " in memory at 0x" + Long.toHexString(relocTableAddr));
Long.toHexString(relocTableAddr));
return; return;
} }
if (relocTableLoadHeader.isInvalidOffset()) { if (relocTableLoadHeader.isInvalidOffset()) {
@ -636,9 +631,9 @@ public class ElfHeader implements StructConverter {
format = TableFormat.RELR; format = TableFormat.RELR;
} }
ElfRelocationTable relocTable = new ElfRelocationTable(reader, ElfRelocationTable relocTable =
this, null, relocTableOffset, relocTableAddr, tableSize, tableEntrySize, new ElfRelocationTable(reader, this, null, relocTableOffset, relocTableAddr,
addendTypeReloc, dynamicSymbolTable, null, format); tableSize, tableEntrySize, addendTypeReloc, dynamicSymbolTable, null, format);
relocationTableList.add(relocTable); relocationTableList.add(relocTable);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
@ -835,11 +830,10 @@ public class ElfHeader implements StructConverter {
int count = (int) (symbolSectionIndexHeader.getSize() / 4); int count = (int) (symbolSectionIndexHeader.getSize() / 4);
int[] indexTable = new int[count]; int[] indexTable = new int[count];
long ptr = reader.getPointerIndex();
try { try {
reader.setPointerIndex(symbolSectionIndexHeader.getOffset()); BinaryReader r = reader.clone(symbolSectionIndexHeader.getOffset());
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
indexTable[i] = reader.readNextInt(); indexTable[i] = r.readNextInt();
} }
} }
catch (IOException e) { catch (IOException e) {
@ -847,9 +841,6 @@ public class ElfHeader implements StructConverter {
Long.toHexString(symbolSectionIndexHeader.getOffset()) + ": " + Long.toHexString(symbolSectionIndexHeader.getOffset()) + ": " +
symbolSectionIndexHeader.getNameAsString()); symbolSectionIndexHeader.getNameAsString());
} }
finally {
reader.setPointerIndex(ptr); // restore reader position
}
return indexTable; return indexTable;
} }
@ -894,11 +885,11 @@ public class ElfHeader implements StructConverter {
int[] symbolSectionIndexTable = int[] symbolSectionIndexTable =
getExtendedSymbolSectionIndexTable(symbolTableSectionHeader); getExtendedSymbolSectionIndexTable(symbolTableSectionHeader);
ElfSymbolTable symbolTable = new ElfSymbolTable(reader, this, ElfSymbolTable symbolTable =
symbolTableSectionHeader, symbolTableSectionHeader.getOffset(), new ElfSymbolTable(reader, this, symbolTableSectionHeader,
symbolTableSectionHeader.getAddress(), symbolTableSectionHeader.getSize(), symbolTableSectionHeader.getOffset(), symbolTableSectionHeader.getAddress(),
symbolTableSectionHeader.getEntrySize(), stringTable, symbolSectionIndexTable, symbolTableSectionHeader.getSize(), symbolTableSectionHeader.getEntrySize(),
isDyanmic); stringTable, symbolSectionIndexTable, isDyanmic);
symbolTableList.add(symbolTable); symbolTableList.add(symbolTable);
if (symbolTable.getAddressOffset() == dynamicSymbolTableAddr) { if (symbolTable.getAddressOffset() == dynamicSymbolTableAddr) {
dynamicSymbolTable = symbolTable; // remember dynamic symbol table dynamicSymbolTable = symbolTable; // remember dynamic symbol table
@ -976,8 +967,9 @@ public class ElfHeader implements StructConverter {
} }
ElfProgramHeader hashTableLoadHeader = getProgramLoadHeaderContaining(hashTableAddr); ElfProgramHeader hashTableLoadHeader = getProgramLoadHeaderContaining(hashTableAddr);
if (hashTableLoadHeader == null) { if (hashTableLoadHeader == null) {
errorConsumer.accept("Failed to locate DT_HASH, DT_GNU_HASH, or DT_GNU_XHASH in memory at 0x" + errorConsumer.accept(
Long.toHexString(hashTableAddr)); "Failed to locate DT_HASH, DT_GNU_HASH, or DT_GNU_XHASH in memory at 0x" +
Long.toHexString(hashTableAddr));
return null; return null;
} }
@ -1001,9 +993,8 @@ public class ElfHeader implements StructConverter {
// NOTE: When parsed from dynamic table and not found via section header parse // NOTE: When parsed from dynamic table and not found via section header parse
// it is assumed that the extended symbol section table is not used. // it is assumed that the extended symbol section table is not used.
return new ElfSymbolTable(reader, this, null, symbolTableOffset, return new ElfSymbolTable(reader, this, null, symbolTableOffset, tableAddr,
tableAddr, tableEntrySize * symCount, tableEntrySize, dynamicStringTable, null, tableEntrySize * symCount, tableEntrySize, dynamicStringTable, null, true);
true);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
throw new AssertException(e); throw new AssertException(e);
@ -1082,8 +1073,7 @@ public class ElfHeader implements StructConverter {
} }
} }
protected void parseSectionHeaders() protected void parseSectionHeaders() throws IOException {
throws IOException {
if (reader == null) { if (reader == null) {
throw new IOException("ELF binary reader is null!"); throw new IOException("ELF binary reader is null!");
} }
@ -1098,13 +1088,11 @@ public class ElfHeader implements StructConverter {
long index = e_shoff + (i * e_shentsize); long index = e_shoff + (i * e_shentsize);
if (!missing && !providerContainsRegion(index, e_shentsize)) { if (!missing && !providerContainsRegion(index, e_shentsize)) {
int unreadCnt = e_shnum - i; int unreadCnt = e_shnum - i;
errorConsumer.accept( errorConsumer.accept(unreadCnt + " of " + e_shnum +
unreadCnt + " of " + e_shnum + " section headers are truncated/missing from file");
" section headers are truncated/missing from file");
missing = true; missing = true;
} }
reader.setPointerIndex(index); sectionHeaders[i] = new ElfSectionHeader(reader.clone(index), this);
sectionHeaders[i] = new ElfSectionHeader(reader, this);
if (sectionHeaders[i].getType() == ElfSectionHeaderConstants.SHT_SYMTAB_SHNDX) { if (sectionHeaders[i].getType() == ElfSectionHeaderConstants.SHT_SYMTAB_SHNDX) {
hasExtendedSymbolSectionIndexTable = true; hasExtendedSymbolSectionIndexTable = true;
} }
@ -1123,21 +1111,18 @@ public class ElfHeader implements StructConverter {
} }
} }
private void parseProgramHeaders() private void parseProgramHeaders() throws IOException {
throws IOException {
boolean missing = false; boolean missing = false;
programHeaders = new ElfProgramHeader[e_phnum]; programHeaders = new ElfProgramHeader[e_phnum];
for (int i = 0; i < e_phnum; ++i) { for (int i = 0; i < e_phnum; ++i) {
long index = e_phoff + (i * e_phentsize); long index = e_phoff + (i * e_phentsize);
if (!missing && !providerContainsRegion(index, e_phentsize)) { if (!missing && !providerContainsRegion(index, e_phentsize)) {
int unreadCnt = e_phnum - i; int unreadCnt = e_phnum - i;
errorConsumer.accept( errorConsumer.accept(unreadCnt + " of " + e_phnum +
unreadCnt + " of " + e_phnum + " program headers are truncated/missing from file");
" program headers are truncated/missing from file");
missing = true; missing = true;
} }
reader.setPointerIndex(index); programHeaders[i] = new ElfProgramHeader(reader.clone(index), this);
programHeaders[i] = new ElfProgramHeader(reader, this);
} }
// TODO: Find sample file which requires this hack to verify its necessity // TODO: Find sample file which requires this hack to verify its necessity
@ -1213,18 +1198,16 @@ public class ElfHeader implements StructConverter {
// which currently considers prelink. // which currently considers prelink.
long minBase = -1; long minBase = -1;
int n = Math.min(e_phnum, MAX_HEADERS_TO_CHECK_FOR_IMAGEBASE); int n = Math.min(e_phnum, MAX_HEADERS_TO_CHECK_FOR_IMAGEBASE);
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
long index = e_phoff + (i * e_phentsize); long index = e_phoff + (i * e_phentsize);
if (!providerContainsRegion(index, e_phentsize)) { if (!providerContainsRegion(index, e_phentsize)) {
break; break;
} }
reader.setPointerIndex(index);
try { try {
int headerType = reader.peekNextInt(); int headerType = reader.readInt(index);
if (headerType == ElfProgramHeaderConstants.PT_LOAD) { if (headerType == ElfProgramHeaderConstants.PT_LOAD) {
ElfProgramHeader header = new ElfProgramHeader(reader, this); ElfProgramHeader header = new ElfProgramHeader(reader.clone(index), this);
minBase = getMinBase(header.getVirtualAddress(), minBase); minBase = getMinBase(header.getVirtualAddress(), minBase);
} }
} }
@ -1979,100 +1962,4 @@ public class ElfHeader implements StructConverter {
return 13; return 13;
} }
private void addSection(ElfSectionHeader newSection) {
++e_shnum;
ElfSectionHeader[] tmp = new ElfSectionHeader[e_shnum];
System.arraycopy(sectionHeaders, 0, tmp, 0, sectionHeaders.length);
sectionHeaders = tmp;
sectionHeaders[e_shnum - 1] = newSection;
if (e_shnum != sectionHeaders.length) {
throw new IllegalStateException();
}
}
/**
* Adds a new section using the specified memory block.
* The memory block is used to setting the address and size.
* As well as, setting the data.
* @param block the memory block
* @param sh_name the byte index into the string table where the name begins
* @return the newly created section
* @throws MemoryAccessException if any of the requested memory block bytes are uninitialized.
*/
public ElfSectionHeader addSection(MemoryBlock block, int sh_name)
throws MemoryAccessException {
ElfSectionHeader newSection = new ElfSectionHeader(this, block, sh_name, getImageBase());
addSection(newSection);
return newSection;
}
/**
* Adds a new section the specifed name and name index.
* The type of the section will be SHT_PROGBITS.
* @param name the actual name of the new section
* @param sh_name the byte index into the string table where the name begins
* @return the newly created section
*/
public ElfSectionHeader addSection(String name, int sh_name) {
return addSection(name, sh_name, ElfSectionHeaderConstants.SHT_PROGBITS);
}
/**
* Adds a new section the specifed name and name index.
* The type of the section will be SHT_PROGBITS.
* @param name the actual name of the new section
* @param sh_name the byte index into the string table where the name begins
* @param type the type of the new section
* @return the newly created section
*/
public ElfSectionHeader addSection(String name, int sh_name, int type) {
ElfSectionHeader newSection = new ElfSectionHeader(this, name, sh_name, type);
addSection(newSection);
return newSection;
}
/**
* Appends the new program header to the end of the existing
* program header table.
* @param ph the new program header
*/
public void addProgramHeader(ElfProgramHeader ph) {
ElfProgramHeader[] tmp = new ElfProgramHeader[programHeaders.length + 1];
int pos = tmp.length - 1;
boolean firstLoad = true;
int firstLoadPos = -1;
/*PT_LOAD segments must be inserted in sorted order*/
if (ph.getType() == ElfProgramHeaderConstants.PT_LOAD) {
for (int i = 0; i < programHeaders.length - 1; ++i) {
if (programHeaders[i].getType() == ElfProgramHeaderConstants.PT_LOAD) {
if (firstLoad) {
firstLoad = false;
firstLoadPos = i;
}
pos = i;
}
}
++pos;
}
System.arraycopy(programHeaders, 0, tmp, 0, pos);
tmp[pos] = ph;
System.arraycopy(programHeaders, pos, tmp, pos + 1, programHeaders.length - pos);
if (ph.getType() == ElfProgramHeaderConstants.PT_LOAD) {
Arrays.sort(tmp, firstLoadPos, pos + 1);
}
programHeaders = tmp;
e_phnum = programHeaders.length;
}
} }

View file

@ -18,6 +18,7 @@ package ghidra.app.util.bin.format.elf;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Objects;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import ghidra.app.util.bin.*; import ghidra.app.util.bin.*;
@ -66,35 +67,31 @@ import ghidra.util.StringUtilities;
public class ElfProgramHeader public class ElfProgramHeader
implements StructConverter, Comparable<ElfProgramHeader>, MemoryLoadable { implements StructConverter, Comparable<ElfProgramHeader>, MemoryLoadable {
protected ElfHeader header; protected final ElfHeader header;
private int p_type; private final int p_type;
private int p_flags; private final int p_flags;
private long p_offset; private long p_offset; // may get altered after instantiation
private long p_vaddr; private final long p_vaddr;
private long p_paddr; private final long p_paddr;
private long p_filesz; private final long p_filesz;
private long p_memsz; private final long p_memsz;
private long p_align; private final long p_align;
private BinaryReader reader; private final BinaryReader reader;
public ElfProgramHeader(BinaryReader reader, ElfHeader header) /**
throws IOException { * Construct {@link ElfProgramHeader}
* @param reader dedicated reader instance positioned to the start of the program header data.
* (the reader supplied will be retained and altered).
* @param header ELF header
* @throws IOException if an IO error occurs during parse
*/
public ElfProgramHeader(BinaryReader reader, ElfHeader header) throws IOException {
this.header = header; this.header = header;
this.reader = reader; this.reader = reader;
if (header.is32Bit()) { if (header.is64Bit()) {
p_type = reader.readNextInt();
p_offset = Integer.toUnsignedLong(reader.readNextInt());
p_vaddr = Integer.toUnsignedLong(reader.readNextInt());
p_paddr = Integer.toUnsignedLong(reader.readNextInt());
p_filesz = Integer.toUnsignedLong(reader.readNextInt());
p_memsz = Integer.toUnsignedLong(reader.readNextInt());
p_flags = reader.readNextInt();
p_align = Integer.toUnsignedLong(reader.readNextInt());
}
else if (header.is64Bit()) {
p_type = reader.readNextInt(); p_type = reader.readNextInt();
p_flags = reader.readNextInt(); p_flags = reader.readNextInt();
p_offset = reader.readNextLong(); p_offset = reader.readNextLong();
@ -104,6 +101,16 @@ public class ElfProgramHeader
p_memsz = reader.readNextLong(); p_memsz = reader.readNextLong();
p_align = reader.readNextLong(); p_align = reader.readNextLong();
} }
else {
p_type = reader.readNextInt();
p_offset = reader.readNextUnsignedInt();
p_vaddr = reader.readNextUnsignedInt();
p_paddr = reader.readNextUnsignedInt();
p_filesz = reader.readNextUnsignedInt();
p_memsz = reader.readNextUnsignedInt();
p_flags = reader.readNextInt();
p_align = reader.readNextUnsignedInt();
}
if (p_memsz > p_filesz) { if (p_memsz > p_filesz) {
//This case occurs when the data segment has both //This case occurs when the data segment has both
@ -115,22 +122,6 @@ public class ElfProgramHeader
} }
} }
/**
* Constructs a new program header with the specified type.
* @param header ELF header
* @param type the new type of the program header
*/
public ElfProgramHeader(ElfHeader header, int type) {
this.header = header;
p_type = type;
p_flags = ElfProgramHeaderConstants.PF_R | ElfProgramHeaderConstants.PF_W |
ElfProgramHeaderConstants.PF_X;
p_align = 0x1000;
p_paddr = 0xffffffff;
p_vaddr = 0xffffffff;
}
/** /**
* Return ElfHeader associated with this program header * Return ElfHeader associated with this program header
* @return ElfHeader * @return ElfHeader
@ -431,9 +422,6 @@ public class ElfProgramHeader
return typeEnum; return typeEnum;
} }
/**
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override @Override
public int compareTo(ElfProgramHeader that) { public int compareTo(ElfProgramHeader that) {
//sort the headers putting 0xffffffff (new guys) //sort the headers putting 0xffffffff (new guys)
@ -457,7 +445,7 @@ public class ElfProgramHeader
@Override @Override
public int hashCode() { public int hashCode() {
return (int) ((31 * p_offset) + (p_offset >>> 32)); return Objects.hash(p_offset);
} }
@Override @Override
@ -466,8 +454,8 @@ public class ElfProgramHeader
return false; return false;
} }
ElfProgramHeader other = (ElfProgramHeader) obj; ElfProgramHeader other = (ElfProgramHeader) obj;
return reader == other.reader && p_type == other.p_type && p_flags == other.p_flags && return p_type == other.p_type && p_flags == other.p_flags && p_offset == other.p_offset &&
p_offset == other.p_offset && p_vaddr == other.p_vaddr && p_paddr == other.p_paddr && p_vaddr == other.p_vaddr && p_paddr == other.p_paddr && p_filesz == other.p_filesz &&
p_filesz == other.p_filesz && p_memsz == other.p_memsz && p_align == other.p_align; p_memsz == other.p_memsz && p_align == other.p_align;
} }
} }

View file

@ -100,8 +100,8 @@ public class ElfRelocation implements StructConverter {
* @return ELF relocation object * @return ELF relocation object
* @throws IOException if an IO or parse error occurs * @throws IOException if an IO or parse error occurs
*/ */
static ElfRelocation createElfRelocation(BinaryReader reader, static ElfRelocation createElfRelocation(BinaryReader reader, ElfHeader elfHeader,
ElfHeader elfHeader, int relocationIndex, boolean withAddend) throws IOException { int relocationIndex, boolean withAddend) throws IOException {
Class<? extends ElfRelocation> elfRelocationClazz = getElfRelocationClass(elfHeader); Class<? extends ElfRelocation> elfRelocationClazz = getElfRelocationClass(elfHeader);
ElfRelocation elfRelocation = getInstance(elfRelocationClazz); ElfRelocation elfRelocation = getInstance(elfRelocationClazz);
elfRelocation.initElfRelocation(reader, elfHeader, relocationIndex, withAddend); elfRelocation.initElfRelocation(reader, elfHeader, relocationIndex, withAddend);
@ -120,9 +120,8 @@ public class ElfRelocation implements StructConverter {
* @return ELF relocation object * @return ELF relocation object
* @throws IOException if an IO or parse error occurs * @throws IOException if an IO or parse error occurs
*/ */
static ElfRelocation createElfRelocation(ElfHeader elfHeader, static ElfRelocation createElfRelocation(ElfHeader elfHeader, int relocationIndex,
int relocationIndex, boolean withAddend, long r_offset, long r_info, long r_addend) boolean withAddend, long r_offset, long r_info, long r_addend) throws IOException {
throws IOException {
Class<? extends ElfRelocation> elfRelocationClazz = getElfRelocationClass(elfHeader); Class<? extends ElfRelocation> elfRelocationClazz = getElfRelocationClass(elfHeader);
ElfRelocation elfRelocation = getInstance(elfRelocationClazz); ElfRelocation elfRelocation = getInstance(elfRelocationClazz);
elfRelocation.initElfRelocation(elfHeader, relocationIndex, withAddend, r_offset, r_info, elfRelocation.initElfRelocation(elfHeader, relocationIndex, withAddend, r_offset, r_info,
@ -218,8 +217,8 @@ public class ElfRelocation implements StructConverter {
private void readEntryData(BinaryReader reader) throws IOException { private void readEntryData(BinaryReader reader) throws IOException {
if (is32bit) { if (is32bit) {
this.r_offset = Integer.toUnsignedLong(reader.readNextInt()); this.r_offset = reader.readNextUnsignedInt();
this.r_info = Integer.toUnsignedLong(reader.readNextInt()); this.r_info = reader.readNextUnsignedInt();
if (hasAddend) { if (hasAddend) {
r_addend = reader.readNextInt(); r_addend = reader.readNextInt();
} }

View file

@ -32,27 +32,27 @@ public class ElfRelocationTable implements ElfFileSection {
DEFAULT, ANDROID, RELR; DEFAULT, ANDROID, RELR;
} }
private TableFormat format; private final TableFormat format;
private ElfSectionHeader sectionToBeRelocated; private final ElfSectionHeader sectionToBeRelocated;
private ElfSymbolTable symbolTable; private final ElfSymbolTable symbolTable;
private ElfSectionHeader relocTableSection; // may be null private final ElfSectionHeader relocTableSection; // may be null
private long fileOffset; private final long fileOffset;
private long addrOffset; private final long addrOffset;
private long length; private final long length;
private long entrySize; private final long entrySize;
private boolean addendTypeReloc; private final boolean addendTypeReloc;
private ElfHeader elfHeader; private final ElfHeader elfHeader;
private ElfRelocation[] relocs; private final ElfRelocation[] relocs;
/** /**
* Construct an Elf Relocation Table * Construct an Elf Relocation Table
* @param reader byte provider reader * @param reader byte provider reader (reader is not retained and position is unaffected)
* @param header elf header * @param header elf header
* @param relocTableSection relocation table section header or null if associated with a dynamic table entry * @param relocTableSection relocation table section header or null if associated with a dynamic table entry
* @param fileOffset relocation table file offset * @param fileOffset relocation table file offset
@ -70,34 +70,30 @@ public class ElfRelocationTable implements ElfFileSection {
long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable, long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable,
ElfSectionHeader sectionToBeRelocated, TableFormat format) throws IOException { ElfSectionHeader sectionToBeRelocated, TableFormat format) throws IOException {
this.elfHeader = header;
this.relocTableSection = relocTableSection; this.relocTableSection = relocTableSection;
this.fileOffset = fileOffset; this.fileOffset = fileOffset;
this.addrOffset = addrOffset; this.addrOffset = addrOffset;
this.length = length; this.length = length;
this.entrySize = entrySize; this.entrySize = (format == TableFormat.DEFAULT && entrySize <= 0)
? ElfRelocation.getStandardRelocationEntrySize(header.is64Bit(), addendTypeReloc)
: entrySize;
this.addendTypeReloc = addendTypeReloc; this.addendTypeReloc = addendTypeReloc;
this.elfHeader = header;
this.format = format; this.format = format;
this.sectionToBeRelocated = sectionToBeRelocated; this.sectionToBeRelocated = sectionToBeRelocated;
this.symbolTable = symbolTable; this.symbolTable = symbolTable;
long ptr = reader.getPointerIndex(); BinaryReader relocReader = reader.clone(fileOffset);
reader.setPointerIndex(fileOffset);
List<ElfRelocation> relocList; List<ElfRelocation> relocList;
if (format == TableFormat.RELR) { if (format == TableFormat.RELR) {
relocList = parseRelrRelocations(reader); relocList = parseRelrRelocations(relocReader);
} }
else if (format == TableFormat.ANDROID) { else if (format == TableFormat.ANDROID) {
relocList = parseAndroidRelocations(reader); relocList = parseAndroidRelocations(relocReader);
} }
else { else {
relocList = parseStandardRelocations(reader); relocList = parseStandardRelocations(relocReader);
} }
reader.setPointerIndex(ptr);
relocs = new ElfRelocation[relocList.size()]; relocs = new ElfRelocation[relocList.size()];
relocList.toArray(relocs); relocList.toArray(relocs);
} }
@ -117,13 +113,8 @@ public class ElfRelocationTable implements ElfFileSection {
return false; return false;
} }
private List<ElfRelocation> parseStandardRelocations(BinaryReader reader) private List<ElfRelocation> parseStandardRelocations(BinaryReader reader) throws IOException {
throws IOException {
List<ElfRelocation> relocations = new ArrayList<>(); List<ElfRelocation> relocations = new ArrayList<>();
if (entrySize <= 0) {
entrySize = ElfRelocation.getStandardRelocationEntrySize(elfHeader.is64Bit(), addendTypeReloc);
}
int nRelocs = (int) (length / entrySize); int nRelocs = (int) (length / entrySize);
for (int relocationIndex = 0; relocationIndex < nRelocs; ++relocationIndex) { for (int relocationIndex = 0; relocationIndex < nRelocs; ++relocationIndex) {
relocations.add(ElfRelocation.createElfRelocation(reader, elfHeader, relocationIndex, relocations.add(ElfRelocation.createElfRelocation(reader, elfHeader, relocationIndex,
@ -148,8 +139,8 @@ public class ElfRelocationTable implements ElfFileSection {
while (entry != 0) { while (entry != 0) {
entry >>>= 1; entry >>>= 1;
if ((entry & 1) != 0) { if ((entry & 1) != 0) {
relocList.add(ElfRelocation.createElfRelocation(elfHeader, relocList.add(ElfRelocation.createElfRelocation(elfHeader, relocList.size(),
relocList.size(), addendTypeReloc, offset, 0, 0)); addendTypeReloc, offset, 0, 0));
} }
offset += entrySize; offset += entrySize;
} }
@ -157,8 +148,7 @@ public class ElfRelocationTable implements ElfFileSection {
return baseOffset + (nBits * entrySize); return baseOffset + (nBits * entrySize);
} }
private List<ElfRelocation> parseRelrRelocations(BinaryReader reader) private List<ElfRelocation> parseRelrRelocations(BinaryReader reader) throws IOException {
throws IOException {
// NOTE: Current implementation supports an entrySize of 8 or 4. This could be // NOTE: Current implementation supports an entrySize of 8 or 4. This could be
// made more flexable if needed (applies to ElfRelrRelocationTableDataType as well) // made more flexable if needed (applies to ElfRelrRelocationTableDataType as well)
@ -183,8 +173,7 @@ public class ElfRelocationTable implements ElfFileSection {
return relocList; return relocList;
} }
private List<ElfRelocation> parseAndroidRelocations(BinaryReader reader) private List<ElfRelocation> parseAndroidRelocations(BinaryReader reader) throws IOException {
throws IOException {
String identifier = reader.readNextAsciiString(4); String identifier = reader.readNextAsciiString(4);
if (!"APS2".equals(identifier)) { if (!"APS2".equals(identifier)) {

View file

@ -18,6 +18,7 @@ package ghidra.app.util.bin.format.elf;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Objects;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
@ -25,8 +26,6 @@ import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.MemoryLoadable; import ghidra.app.util.bin.format.MemoryLoadable;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.StringUtilities; import ghidra.util.StringUtilities;
@ -73,58 +72,63 @@ import ghidra.util.StringUtilities;
public class ElfSectionHeader implements StructConverter, MemoryLoadable { public class ElfSectionHeader implements StructConverter, MemoryLoadable {
private int sh_name; private final BinaryReader reader;
private int sh_type; private final ElfHeader header;
private long sh_flags;
private long sh_addr;
private long sh_offset;
private long sh_size;
private int sh_link;
private int sh_info;
private long sh_addralign;
private long sh_entsize;
private BinaryReader reader; private final int sh_name;
private final int sh_type;
private final long sh_flags;
private long sh_addr; // may get altered after instantiation
private final long sh_offset;
private final long sh_size;
private final int sh_link;
private final int sh_info;
private final long sh_addralign;
private final long sh_entsize;
private ElfHeader header; private String name; // delayed initialization
private String name;
private byte[] data;
private boolean modified = false;
private boolean bytesChanged = false;
private ElfCompressedSectionHeader compressedHeader; private ElfCompressedSectionHeader compressedHeader;
/**
* Construct {@link ElfSectionHeader}
* @param reader dedicated reader instance positioned to the start of the program header data.
* (the reader supplied will be retained and altered).
* @param header ELF header
* @throws IOException if an IO error occurs during parse
*/
public ElfSectionHeader(BinaryReader reader, ElfHeader header) throws IOException { public ElfSectionHeader(BinaryReader reader, ElfHeader header) throws IOException {
this.reader = reader; this.reader = reader;
this.header = header; this.header = header;
sh_name = reader.readNextInt(); sh_name = reader.readNextInt();
sh_type = reader.readNextInt(); sh_type = reader.readNextInt();
if (header.is32Bit()) { if (header.is64Bit()) {
sh_flags = Integer.toUnsignedLong(reader.readNextInt());
sh_addr = Integer.toUnsignedLong(reader.readNextInt());
sh_offset = Integer.toUnsignedLong(reader.readNextInt());
sh_size = Integer.toUnsignedLong(reader.readNextInt());
}
else if (header.is64Bit()) {
sh_flags = reader.readNextLong(); sh_flags = reader.readNextLong();
sh_addr = reader.readNextLong(); sh_addr = reader.readNextLong();
sh_offset = reader.readNextLong(); sh_offset = reader.readNextLong();
sh_size = reader.readNextLong(); sh_size = reader.readNextLong();
} }
else { // assume 32-bit
sh_flags = reader.readNextUnsignedInt();
sh_addr = reader.readNextUnsignedInt();
sh_offset = reader.readNextUnsignedInt();
sh_size = reader.readNextUnsignedInt();
}
sh_link = reader.readNextInt(); sh_link = reader.readNextInt();
sh_info = reader.readNextInt(); sh_info = reader.readNextInt();
if (header.is32Bit()) { if (header.is64Bit()) {
sh_addralign = Integer.toUnsignedLong(reader.readNextInt());
sh_entsize = Integer.toUnsignedLong(reader.readNextInt());
}
else if (header.is64Bit()) {
sh_addralign = reader.readNextLong(); sh_addralign = reader.readNextLong();
sh_entsize = reader.readNextLong(); sh_entsize = reader.readNextLong();
} }
else { // assume 32-bit
sh_addralign = reader.readNextUnsignedInt();
sh_entsize = reader.readNextUnsignedInt();
}
if ((sh_flags & ElfSectionHeaderConstants.SHF_COMPRESSED) != 0) { if ((sh_flags & ElfSectionHeaderConstants.SHF_COMPRESSED) != 0) {
compressedHeader = readCompressedSectionHeader(); compressedHeader = readCompressedSectionHeader();
@ -148,7 +152,6 @@ public class ElfSectionHeader implements StructConverter, MemoryLoadable {
} }
catch (IOException e) { catch (IOException e) {
Msg.warn(this, "Error reading compressed section information: " + e); Msg.warn(this, "Error reading compressed section information: " + e);
Msg.debug(this, "Error reading compressed section information", e);
} }
return null; return null;
} }
@ -159,56 +162,6 @@ public class ElfSectionHeader implements StructConverter, MemoryLoadable {
endOffset <= streamLength; endOffset <= streamLength;
} }
ElfSectionHeader(ElfHeader header, MemoryBlock block, int sh_name, long imageBase)
throws MemoryAccessException {
this.header = header;
this.sh_name = sh_name;
if (block.isInitialized()) {
sh_type = ElfSectionHeaderConstants.SHT_PROGBITS;
}
else {
sh_type = ElfSectionHeaderConstants.SHT_NOBITS;
}
sh_flags = ElfSectionHeaderConstants.SHF_ALLOC | ElfSectionHeaderConstants.SHF_WRITE |
ElfSectionHeaderConstants.SHF_EXECINSTR;
sh_addr = block.getStart().getOffset();
sh_offset = block.getStart().getAddressableWordOffset() - imageBase;
sh_size = block.getSize();
sh_link = 0;
sh_info = 0;
sh_addralign = 0;
sh_entsize = 0;
name = block.getName();
data = new byte[(int) sh_size];
if (block.isInitialized()) {
block.getBytes(block.getStart(), data);
}
modified = true;
}
ElfSectionHeader(ElfHeader header, String name, int sh_name, int type) {
this.header = header;
this.name = name;
this.sh_name = sh_name;
this.sh_type = type;
sh_flags = ElfSectionHeaderConstants.SHF_ALLOC | ElfSectionHeaderConstants.SHF_WRITE |
ElfSectionHeaderConstants.SHF_EXECINSTR;
sh_link = 0;
sh_info = 0;
sh_addralign = 0;
sh_entsize = 0;
data = new byte[0];
sh_size = 0;
sh_addr = -1;
sh_offset = -1;
}
/** /**
* Return ElfHeader associated with this section * Return ElfHeader associated with this section
* @return ElfHeader * @return ElfHeader
@ -538,24 +491,6 @@ public class ElfSectionHeader implements StructConverter, MemoryLoadable {
return reader; return reader;
} }
/**
* Returns true if the data bytes have changed for this section.
* @return true if the data bytes have changed for this section
*/
public boolean isBytesChanged() {
return bytesChanged;
}
/**
* Returns true if this section has been modified.
* A modified section requires that a new program header
* get created.
* @return true if this section has been modified
*/
public boolean isModified() {
return modified;
}
/** /**
* Sets the start address of this section. * Sets the start address of this section.
* @param addr the new start address of this section * @param addr the new start address of this section
@ -626,7 +561,7 @@ public class ElfSectionHeader implements StructConverter, MemoryLoadable {
@Override @Override
public int hashCode() { public int hashCode() {
return (int) ((17 * sh_offset) + (sh_offset >>> 32)); return Objects.hash(sh_offset);
} }
@Override @Override
@ -635,11 +570,10 @@ public class ElfSectionHeader implements StructConverter, MemoryLoadable {
return false; return false;
} }
ElfSectionHeader other = (ElfSectionHeader) obj; ElfSectionHeader other = (ElfSectionHeader) obj;
return reader == other.reader && sh_name == other.sh_name && sh_type == other.sh_type && return sh_name == other.sh_name && sh_type == other.sh_type && sh_flags == other.sh_flags &&
sh_flags == other.sh_flags && sh_addr == other.sh_addr && sh_addr == other.sh_addr && sh_offset == other.sh_offset && sh_size == other.sh_size &&
sh_offset == other.sh_offset && sh_size == other.sh_size && sh_link == other.sh_link && sh_link == other.sh_link && sh_info == other.sh_info &&
sh_info == other.sh_info && sh_addralign == other.sh_addralign && sh_addralign == other.sh_addralign && sh_entsize == other.sh_entsize;
sh_entsize == other.sh_entsize;
} }
} }

View file

@ -138,27 +138,27 @@ public class ElfSectionHeaderConstants {
// Section Header Flag Bits // Section Header Flag Bits
/**The section contains data that should be writable during process execution.*/ /**The section contains data that should be writable during process execution.*/
public static final int SHF_WRITE = (1 << 0); public static final int SHF_WRITE = 0x1;
/**The section occupies memory during execution*/ /**The section occupies memory during execution*/
public static final int SHF_ALLOC = (1 << 1); public static final int SHF_ALLOC = 0x2;
/**The section contains executable machine instructions.*/ /**The section contains executable machine instructions.*/
public static final int SHF_EXECINSTR = (1 << 2); public static final int SHF_EXECINSTR = 0x4;
/**The section might be merged*/ /**The section might be merged*/
public static final int SHF_MERGE = (1 << 4); public static final int SHF_MERGE = 0x10;
/**The section contains null-terminated strings*/ /**The section contains null-terminated strings*/
public static final int SHF_STRINGS = (1 << 5); public static final int SHF_STRINGS = 0x20;
/**sh_info contains SHT index*/ /**sh_info contains SHT index*/
public static final int SHF_INFO_LINK = (1 << 6); public static final int SHF_INFO_LINK = 0x40;
/**Preserve order after combining*/ /**Preserve order after combining*/
public static final int SHF_LINK_ORDER = (1 << 7); public static final int SHF_LINK_ORDER = 0x80;
/**Non-standard OS specific handling required*/ /**Non-standard OS specific handling required*/
public static final int SHF_OS_NONCONFORMING = (1 << 8); public static final int SHF_OS_NONCONFORMING = 0x100;
/**The section is member of a group.*/ /**The section is member of a group.*/
public static final int SHF_GROUP = (1 << 9); public static final int SHF_GROUP = 0x200;
/**The section that holds thread-local data.*/ /**The section that holds thread-local data.*/
public static final int SHF_TLS = (1 << 10); public static final int SHF_TLS = 0x400;
/**The bytes of the section are compressed */ /**The bytes of the section are compressed */
public static final int SHF_COMPRESSED = (1 << 11); public static final int SHF_COMPRESSED = 0x800;
/**This section is excluded from the final executable or shared library.*/ /**This section is excluded from the final executable or shared library.*/
public static final int SHF_EXCLUDE = 0x80000000; public static final int SHF_EXCLUDE = 0x80000000;
/**The section contains OS-specific data.*/ /**The section contains OS-specific data.*/

View file

@ -23,12 +23,12 @@ import ghidra.util.exception.DuplicateNameException;
public class ElfStringTable implements ElfFileSection { public class ElfStringTable implements ElfFileSection {
private ElfHeader header; private final ElfHeader header;
private ElfSectionHeader stringTableSection; // may be null private final ElfSectionHeader stringTableSection; // may be null
private long fileOffset; private final long fileOffset;
private long addrOffset; private final long addrOffset;
private long length; private final long length;
/** /**
* Construct and parse an Elf string table * Construct and parse an Elf string table
@ -49,7 +49,7 @@ public class ElfStringTable implements ElfFileSection {
/** /**
* Read string from table at specified relative table offset * Read string from table at specified relative table offset
* @param reader byte reader * @param reader byte reader (position remains unchanged)
* @param stringOffset table relative string offset * @param stringOffset table relative string offset
* @return string or null on error * @return string or null on error
*/ */

View file

@ -92,14 +92,14 @@ public class ElfSymbol {
public static final byte STV_PROTECTED = 3; public static final byte STV_PROTECTED = 3;
private ElfSymbolTable symbolTable; private ElfSymbolTable symbolTable;
private int symbolTableIndex; private final int symbolTableIndex;
private int st_name; private final int st_name;
private long st_value; private final long st_value;
private long st_size; private final long st_size;
private byte st_info; private final byte st_info;
private byte st_other; private final byte st_other;
private short st_shndx; private final short st_shndx;
private String nameAsString; private String nameAsString;
@ -107,28 +107,36 @@ public class ElfSymbol {
* Construct a new special null symbol which corresponds to symbol index 0. * Construct a new special null symbol which corresponds to symbol index 0.
*/ */
public ElfSymbol() { public ElfSymbol() {
this.nameAsString = ""; symbolTableIndex = 0;
st_name = 0;
st_value = 0;
st_size = 0;
st_info = 0;
st_other = 0;
st_shndx = 0;
nameAsString = "";
} }
/** /**
* Construct a normal ElfSymbol. * Construct a normal ElfSymbol.
* Warning! the routine initSymbolName() must be called on the symbol later * Warning! the routine initSymbolName() must be called on the symbol later
* to initialize the string name. This is a performance enhancement. * to initialize the string name. This is a performance enhancement.
* @param reader to read symbol from * @param reader to read symbol entry at current position
* (reader is not retained, position is altered)
* @param symbolIndex index of the symbol to read * @param symbolIndex index of the symbol to read
* @param symbolTable symbol table to associate the symbol to * @param symbolTable symbol table to associate the symbol to
* @param header else header * @param header ELF header
* @throws IOException if an issue with reading occurs * @throws IOException if an IO error occurs during parse
*/ */
public ElfSymbol(BinaryReader reader, int symbolIndex, public ElfSymbol(BinaryReader reader, int symbolIndex, ElfSymbolTable symbolTable,
ElfSymbolTable symbolTable, ElfHeader header) throws IOException { ElfHeader header) throws IOException {
this.symbolTable = symbolTable; this.symbolTable = symbolTable;
this.symbolTableIndex = symbolIndex; this.symbolTableIndex = symbolIndex;
if (header.is32Bit()) { if (header.is32Bit()) {
st_name = reader.readNextInt(); st_name = reader.readNextInt();
st_value = Integer.toUnsignedLong(reader.readNextInt()); st_value = reader.readNextUnsignedInt();
st_size = Integer.toUnsignedLong(reader.readNextInt()); st_size = reader.readNextUnsignedInt();
st_info = reader.readNextByte(); st_info = reader.readNextByte();
st_other = reader.readNextByte(); st_other = reader.readNextByte();
st_shndx = reader.readNextShort(); st_shndx = reader.readNextShort();
@ -171,7 +179,7 @@ public class ElfSymbol {
* at the same time the reading buffer will jump around and significantly * at the same time the reading buffer will jump around and significantly
* degrade reading performance. * degrade reading performance.
* *
* @param reader to read from * @param reader to read from (position remains unchanged)
* @param stringTable stringTable to initialize symbol name * @param stringTable stringTable to initialize symbol name
*/ */
public void initSymbolName(BinaryReader reader, ElfStringTable stringTable) { public void initSymbolName(BinaryReader reader, ElfStringTable stringTable) {
@ -492,8 +500,8 @@ public class ElfSymbol {
return nameAsString + " - " + "st_value: 0x" + Long.toHexString(st_value) + " - " + return nameAsString + " - " + "st_value: 0x" + Long.toHexString(st_value) + " - " +
"st_size: 0x" + Long.toHexString(st_size) + " - " + "st_info: 0x" + "st_size: 0x" + Long.toHexString(st_size) + " - " + "st_info: 0x" +
Integer.toHexString(Byte.toUnsignedInt(st_info)) + " - " + "st_other: 0x" + Integer.toHexString(Byte.toUnsignedInt(st_info)) + " - " + "st_other: 0x" +
Integer.toHexString(Byte.toUnsignedInt(st_other)) + Integer.toHexString(Byte.toUnsignedInt(st_other)) + " - " + "st_shndx: 0x" +
" - " + "st_shndx: 0x" + Integer.toHexString(Short.toUnsignedInt(st_shndx)); Integer.toHexString(Short.toUnsignedInt(st_shndx));
} }
} }

View file

@ -29,23 +29,23 @@ import ghidra.util.exception.DuplicateNameException;
*/ */
public class ElfSymbolTable implements ElfFileSection { public class ElfSymbolTable implements ElfFileSection {
private ElfStringTable stringTable; private final ElfStringTable stringTable;
private ElfSectionHeader symbolTableSection; // may be null private final ElfSectionHeader symbolTableSection; // may be null
private int[] symbolSectionIndexTable; private final int[] symbolSectionIndexTable;
private long fileOffset; private final long fileOffset;
private long addrOffset; private final long addrOffset;
private long length; private final long length;
private long entrySize; private final long entrySize;
private int symbolCount; private final int symbolCount;
private boolean is32bit; private final boolean is32bit;
private boolean isDynamic; private final boolean isDynamic;
private ElfSymbol[] symbols; private final ElfSymbol[] symbols;
/** /**
* Construct and parse an Elf symbol table * Construct and parse an Elf symbol table
* @param reader byte reader * @param reader byte reader (reader is not retained and position is unaffected)
* @param header elf header * @param header elf header
* @param symbolTableSection string table section header or null if associated with a dynamic table entry * @param symbolTableSection string table section header or null if associated with a dynamic table entry
* @param fileOffset symbol table file offset * @param fileOffset symbol table file offset
@ -74,36 +74,33 @@ public class ElfSymbolTable implements ElfFileSection {
this.symbolSectionIndexTable = symbolSectionIndexTable; this.symbolSectionIndexTable = symbolSectionIndexTable;
this.isDynamic = isDynamic; this.isDynamic = isDynamic;
long ptr = reader.getPointerIndex(); BinaryReader symTableReader = reader.clone(fileOffset);
reader.setPointerIndex(fileOffset);
List<ElfSymbol> symbolList = new ArrayList<>(); List<ElfSymbol> symbolList = new ArrayList<>();
symbolCount = (int) (length / entrySize); symbolCount = (int) (length / entrySize);
long entryPos = reader.getPointerIndex();
// load the all the symbol entries first, don't initialize the string name // load the all the symbol entries first, don't initialize the string name
// that will be done later to help localize memory access // that will be done later to help localize memory access
long entryPos = fileOffset;
for (int i = 0; i < symbolCount; i++) { for (int i = 0; i < symbolCount; i++) {
// Reposition reader to start of symbol element since ElfSymbol object // Reposition reader to start of symbol element since ElfSymbol object
// may not consume all symbol element data // may not consume all symbol element data
reader.setPointerIndex(entryPos); symTableReader.setPointerIndex(entryPos);
ElfSymbol sym = new ElfSymbol(reader, i, this, header); ElfSymbol sym = new ElfSymbol(symTableReader, i, this, header);
symbolList.add(sym); symbolList.add(sym);
entryPos += entrySize; entryPos += entrySize;
} }
// sort the entries by the index in the string table, so don't jump around reading // sort the entries by the index in the string table, so don't jump around reading
List<ElfSymbol> sortedList = symbolList.stream().sorted( List<ElfSymbol> sortedList = symbolList.stream()
(o1, o2) -> Integer.compare(o1.getName(), o2.getName())).collect(Collectors.toList()); .sorted((o1, o2) -> Integer.compare(o1.getName(), o2.getName()))
.collect(Collectors.toList());
// initialize the Symbol string names from string table // initialize the Symbol string names from string table
for (ElfSymbol sym : sortedList) { for (ElfSymbol sym : sortedList) {
sym.initSymbolName(reader, stringTable); sym.initSymbolName(symTableReader, stringTable);
} }
reader.setPointerIndex(ptr);
symbols = new ElfSymbol[symbolList.size()]; symbols = new ElfSymbol[symbolList.size()];
symbolList.toArray(symbols); symbolList.toArray(symbols);
} }