mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-3620 Complete changes to eliminate mutability of ELF related headers
intended for import/loading only.
This commit is contained in:
parent
28cc3af5e0
commit
8fb5a88b89
12 changed files with 355 additions and 542 deletions
|
@ -292,7 +292,7 @@ public class BinaryReader {
|
|||
* For example, if current index was 123 and align value was 16, then current index would
|
||||
* be advanced to 128.
|
||||
*
|
||||
* @param alignValue
|
||||
* @param alignValue position index alignment
|
||||
* @return the number of bytes required to align (0..alignValue-1)
|
||||
*/
|
||||
public int align(int alignValue) {
|
||||
|
@ -305,9 +305,11 @@ public class BinaryReader {
|
|||
* A convenience method for setting the index using a 32 bit 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) {
|
||||
this.currentIndex = Integer.toUnsignedLong(index);
|
||||
public long setPointerIndex(int index) {
|
||||
return setPointerIndex(Integer.toUnsignedLong(index));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -316,9 +318,12 @@ public class BinaryReader {
|
|||
* to operate as a pseudo-iterator.
|
||||
*
|
||||
* @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) {
|
||||
this.currentIndex = index;
|
||||
public long setPointerIndex(long index) {
|
||||
long oldIndex = currentIndex;
|
||||
currentIndex = index;
|
||||
return oldIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -52,79 +52,85 @@ import ghidra.util.StringUtilities;
|
|||
*/
|
||||
public class ElfDynamic {
|
||||
|
||||
private ElfHeader elf;
|
||||
private final ElfHeader elf;
|
||||
|
||||
private int d_tag;
|
||||
private long d_val;
|
||||
private final int d_tag;
|
||||
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;
|
||||
if (elf.is32Bit()) {
|
||||
d_tag = reader.readNextInt();
|
||||
d_val = Integer.toUnsignedLong(reader.readNextInt());
|
||||
}
|
||||
else {
|
||||
d_val = reader.readNextUnsignedInt();
|
||||
}
|
||||
else {
|
||||
d_tag = (int) reader.readNextLong();
|
||||
d_val = reader.readNextLong();
|
||||
}
|
||||
}
|
||||
d_val = reader.readNextLong();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ELF dynamic with the specified tag and value.
|
||||
* @param tag the tag (or type) of this dynamic
|
||||
* @param value the value (or pointer) of this dynamic
|
||||
* @param elf the elf header
|
||||
*/
|
||||
/**
|
||||
* Constructs a new ELF dynamic with the specified tag and value.
|
||||
* @param tag the tag (or type) of this dynamic
|
||||
* @param value the value (or pointer) of this dynamic
|
||||
* @param elf the elf header
|
||||
*/
|
||||
public ElfDynamic(int tag, long value, ElfHeader elf) {
|
||||
this.d_tag = tag;
|
||||
this.d_val = value;
|
||||
this.d_tag = tag;
|
||||
this.d_val = value;
|
||||
this.elf = elf;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ELF dynamic with the specified (enum) tag and value.
|
||||
* @param tag the (enum) tag (or type) of this dynamic
|
||||
* @param value the value (or pointer) of this dynamic
|
||||
* @param elf the elf header
|
||||
*/
|
||||
/**
|
||||
* Constructs a new ELF dynamic with the specified (enum) tag and value.
|
||||
* @param tag the (enum) tag (or type) of this dynamic
|
||||
* @param value the value (or pointer) of this dynamic
|
||||
* @param elf the elf header
|
||||
*/
|
||||
public ElfDynamic(ElfDynamicType tag, long value, ElfHeader elf) {
|
||||
this(tag.value, value, elf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that controls the interpretation of the
|
||||
* the d_val and/or d_ptr.
|
||||
* @return the tag (or type) of this dynamic
|
||||
*/
|
||||
/**
|
||||
* Returns the value that controls the interpretation of the
|
||||
* the d_val and/or d_ptr.
|
||||
* @return the tag (or type) of this dynamic
|
||||
*/
|
||||
public int getTag() {
|
||||
return d_tag;
|
||||
}
|
||||
return d_tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enum value that controls the interpretation of the
|
||||
* the d_val and/or d_ptr (or null if unknown).
|
||||
* @return the enum tag (or type) of this dynamic or null if unknown
|
||||
*/
|
||||
/**
|
||||
* Returns the enum value that controls the interpretation of the
|
||||
* the d_val and/or d_ptr (or null if unknown).
|
||||
* @return the enum tag (or type) of this dynamic or null if unknown
|
||||
*/
|
||||
public ElfDynamicType getTagType() {
|
||||
return elf.getDynamicType(d_tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
*/
|
||||
public long getValue() {
|
||||
return d_val;
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
*/
|
||||
public long getValue() {
|
||||
return d_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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".
|
||||
* @return 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".
|
||||
* @return a string representing the d_tag value
|
||||
*/
|
||||
public String getTagAsString() {
|
||||
ElfDynamicType tagType = getTagType();
|
||||
if (tagType != null) {
|
||||
|
@ -138,12 +144,11 @@ public class ElfDynamic {
|
|||
return getTagAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @return the size in bytes of this object.
|
||||
*/
|
||||
public int sizeof() {
|
||||
return elf.is32Bit() ? 8 : 16;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -35,33 +35,36 @@ import ghidra.util.exception.NotFoundException;
|
|||
*/
|
||||
public class ElfDynamicTable implements ElfFileSection {
|
||||
|
||||
private List<ElfDynamic> dynamics = new ArrayList<ElfDynamic>();
|
||||
private final List<ElfDynamic> dynamics = new ArrayList<ElfDynamic>();
|
||||
|
||||
private ElfHeader header;
|
||||
private long fileOffset;
|
||||
private long addrOffset;
|
||||
private final ElfHeader header;
|
||||
private final long fileOffset;
|
||||
private final long addrOffset;
|
||||
|
||||
public ElfDynamicTable(BinaryReader reader, ElfHeader header,
|
||||
long fileOffset, long addrOffset) throws IOException {
|
||||
|
||||
long oldptr = reader.getPointerIndex();
|
||||
/**
|
||||
* Construct an ELF Dynamic data table
|
||||
* @param reader byte provider reader (reader is not retained and position is unaffected)
|
||||
* @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.fileOffset = fileOffset;
|
||||
this.addrOffset = addrOffset;
|
||||
|
||||
reader.setPointerIndex(fileOffset);
|
||||
|
||||
// Collect set of all _DYNAMIC array tags specified in .dynamic section
|
||||
BinaryReader entryReader = reader.clone(fileOffset);
|
||||
while (true) {
|
||||
ElfDynamic dyn = new ElfDynamic(reader, header);
|
||||
ElfDynamic dyn = new ElfDynamic(entryReader, header);
|
||||
dynamics.add(dyn);
|
||||
if (dyn.getTag() == ElfDynamicType.DT_NULL.value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
reader.setPointerIndex(oldptr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,8 +122,7 @@ public class ElfDynamicTable implements ElfFileSection {
|
|||
* @throws NotFoundException if requested value type not found
|
||||
*/
|
||||
public long getDynamicValue(long type) throws NotFoundException {
|
||||
for (int i = 0; i < dynamics.size(); i++) {
|
||||
ElfDynamic dyn = dynamics.get(i);
|
||||
for (ElfDynamic dyn : dynamics) {
|
||||
if (dyn.getTag() == type) {
|
||||
return dyn.getValue();
|
||||
}
|
||||
|
@ -143,8 +145,7 @@ public class ElfDynamicTable implements ElfFileSection {
|
|||
* @return true if dynamic value exists
|
||||
*/
|
||||
public boolean containsDynamicValue(long type) {
|
||||
for (int i = 0; i < dynamics.size(); i++) {
|
||||
ElfDynamic dyn = dynamics.get(i);
|
||||
for (ElfDynamic dyn : dynamics) {
|
||||
if (dyn.getTag() == type) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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.ElfLoadAdapter;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
@ -44,39 +42,41 @@ public class ElfHeader implements StructConverter {
|
|||
private HashMap<Integer, ElfSectionHeaderType> sectionHeaderTypeMap;
|
||||
private HashMap<Integer, ElfDynamicType> dynamicTypeMap;
|
||||
|
||||
private ByteProvider provider; // original byte provider
|
||||
private BinaryReader reader; // unlimited reader
|
||||
private ElfLoadAdapter elfLoadAdapter = new ElfLoadAdapter();
|
||||
private final ByteProvider provider; // original byte provider
|
||||
private final BinaryReader reader; // unlimited reader
|
||||
|
||||
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")
|
||||
private byte e_ident_version; //file version
|
||||
private byte e_ident_osabi; //operating system and abi
|
||||
private byte e_ident_abiversion; //abi version
|
||||
private final byte e_ident_magic_num; //magic number
|
||||
private final String e_ident_magic_str; //magic string
|
||||
private final byte e_ident_class; //file class
|
||||
private final byte e_ident_data; //data encoding
|
||||
@SuppressWarnings("unused")
|
||||
private byte[] e_ident_pad; //padding
|
||||
private short e_type; //object file type
|
||||
private short e_machine; //target architecture
|
||||
private int e_version; //object file version
|
||||
private long e_entry; //executable entry point
|
||||
private long e_phoff; //program header table offset
|
||||
private long e_shoff; //section header table offset
|
||||
private int e_flags; //processor-specific flags
|
||||
private short e_ehsize; //elf header size
|
||||
private short e_phentsize; //size of entries in the program header table
|
||||
private int e_phnum; //number of enties in the program header table (may be extended and may not be preserved)
|
||||
private short e_shentsize; //size of entries in the section header table
|
||||
private int e_shnum; //number of enties in the section header table (may be extended and may not be preserved)
|
||||
private int e_shstrndx; //section index of the section name string table (may be extended and may not be preserved)
|
||||
private final byte e_ident_version; //file version
|
||||
private final byte e_ident_osabi; //operating system and abi
|
||||
private final byte e_ident_abiversion; //abi version
|
||||
@SuppressWarnings("unused")
|
||||
private final byte[] e_ident_pad; //padding
|
||||
private final short e_type; //object file type
|
||||
private final short e_machine; //target architecture
|
||||
private final int e_version; //object file version
|
||||
private final long e_entry; //executable entry point
|
||||
private final long e_phoff; //program header table offset
|
||||
private final long e_shoff; //section header table offset
|
||||
private final int e_flags; //processor-specific flags
|
||||
private final short e_ehsize; //elf header size
|
||||
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 boolean parsed = false;
|
||||
private boolean parsedSectionHeaders = false;
|
||||
|
||||
private ElfLoadAdapter elfLoadAdapter = new ElfLoadAdapter();
|
||||
|
||||
private ElfSectionHeader section0 = null;
|
||||
private ElfSectionHeader[] sectionHeaders = new ElfSectionHeader[0];
|
||||
private ElfProgramHeader[] programHeaders = new ElfProgramHeader[0];
|
||||
|
@ -108,31 +108,6 @@ public class ElfHeader implements StructConverter {
|
|||
this.errorConsumer = errorConsumer != null ? errorConsumer : msg -> {
|
||||
/* 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 {
|
||||
|
||||
if (!Arrays.equals(ElfConstants.MAGIC_BYTES,
|
||||
|
@ -179,41 +154,63 @@ public class ElfHeader implements StructConverter {
|
|||
e_ehsize = 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_shnum = reader.readNextUnsignedShort();
|
||||
|
||||
e_shstrndx = Short.toUnsignedInt(reader.readNextShort());
|
||||
|
||||
if (e_shnum == 0 ||
|
||||
e_shnum >= Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_LORESERVE)) {
|
||||
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
|
||||
int shnum = reader.readNextUnsignedShort();
|
||||
if (shnum == 0 ||
|
||||
shnum >= Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_LORESERVE)) {
|
||||
shnum = readExtendedSectionHeaderCount(); // use extended stored section header count
|
||||
}
|
||||
e_shnum = shnum;
|
||||
|
||||
int shstrndx = reader.readNextUnsignedShort();
|
||||
if (e_shnum == 0) {
|
||||
e_shstrndx = 0;
|
||||
shstrndx = 0;
|
||||
}
|
||||
else if (e_shstrndx == Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_XINDEX)) {
|
||||
e_shstrndx = readExtendedSectionHeaderStringTableIndex();
|
||||
else if (shstrndx == Short.toUnsignedInt(ElfSectionHeaderConstants.SHN_XINDEX)) {
|
||||
shstrndx = readExtendedSectionHeaderStringTableIndex();
|
||||
}
|
||||
e_shstrndx = shstrndx;
|
||||
}
|
||||
catch (IOException 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 {
|
||||
if (section0 == null && e_shoff != 0) {
|
||||
if (!providerContainsRegion(e_shoff, e_shentsize)) {
|
||||
return null;
|
||||
}
|
||||
reader.setPointerIndex(e_shoff);
|
||||
section0 = new ElfSectionHeader(reader, this);
|
||||
section0 = new ElfSectionHeader(reader.clone(e_shoff), this);
|
||||
}
|
||||
return section0;
|
||||
}
|
||||
|
@ -544,18 +541,17 @@ public class ElfHeader implements StructConverter {
|
|||
format = TableFormat.RELR;
|
||||
}
|
||||
|
||||
ElfRelocationTable relocTable = new ElfRelocationTable(reader,
|
||||
this, section, section.getOffset(), section.getAddress(), section.getSize(),
|
||||
section.getEntrySize(), addendTypeReloc, symbolTable, sectionToBeRelocated,
|
||||
format);
|
||||
ElfRelocationTable relocTable =
|
||||
new ElfRelocationTable(reader, this, section, section.getOffset(),
|
||||
section.getAddress(), section.getSize(), section.getEntrySize(),
|
||||
addendTypeReloc, symbolTable, sectionToBeRelocated, format);
|
||||
|
||||
relocationTableList.add(relocTable);
|
||||
}
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
errorConsumer
|
||||
.accept("Failed to process relocation section " + section.getNameAsString() +
|
||||
": " + e.getMessage());
|
||||
errorConsumer.accept("Failed to process relocation section " +
|
||||
section.getNameAsString() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -607,9 +603,8 @@ public class ElfHeader implements StructConverter {
|
|||
|
||||
ElfProgramHeader relocTableLoadHeader = getProgramLoadHeaderContaining(relocTableAddr);
|
||||
if (relocTableLoadHeader == null) {
|
||||
errorConsumer
|
||||
.accept("Failed to locate " + relocTableAddrType.name + " in memory at 0x" +
|
||||
Long.toHexString(relocTableAddr));
|
||||
errorConsumer.accept("Failed to locate " + relocTableAddrType.name +
|
||||
" in memory at 0x" + Long.toHexString(relocTableAddr));
|
||||
return;
|
||||
}
|
||||
if (relocTableLoadHeader.isInvalidOffset()) {
|
||||
|
@ -636,9 +631,9 @@ public class ElfHeader implements StructConverter {
|
|||
format = TableFormat.RELR;
|
||||
}
|
||||
|
||||
ElfRelocationTable relocTable = new ElfRelocationTable(reader,
|
||||
this, null, relocTableOffset, relocTableAddr, tableSize, tableEntrySize,
|
||||
addendTypeReloc, dynamicSymbolTable, null, format);
|
||||
ElfRelocationTable relocTable =
|
||||
new ElfRelocationTable(reader, this, null, relocTableOffset, relocTableAddr,
|
||||
tableSize, tableEntrySize, addendTypeReloc, dynamicSymbolTable, null, format);
|
||||
relocationTableList.add(relocTable);
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
|
@ -835,11 +830,10 @@ public class ElfHeader implements StructConverter {
|
|||
int count = (int) (symbolSectionIndexHeader.getSize() / 4);
|
||||
int[] indexTable = new int[count];
|
||||
|
||||
long ptr = reader.getPointerIndex();
|
||||
try {
|
||||
reader.setPointerIndex(symbolSectionIndexHeader.getOffset());
|
||||
BinaryReader r = reader.clone(symbolSectionIndexHeader.getOffset());
|
||||
for (int i = 0; i < count; i++) {
|
||||
indexTable[i] = reader.readNextInt();
|
||||
indexTable[i] = r.readNextInt();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -847,9 +841,6 @@ public class ElfHeader implements StructConverter {
|
|||
Long.toHexString(symbolSectionIndexHeader.getOffset()) + ": " +
|
||||
symbolSectionIndexHeader.getNameAsString());
|
||||
}
|
||||
finally {
|
||||
reader.setPointerIndex(ptr); // restore reader position
|
||||
}
|
||||
|
||||
return indexTable;
|
||||
}
|
||||
|
@ -894,11 +885,11 @@ public class ElfHeader implements StructConverter {
|
|||
int[] symbolSectionIndexTable =
|
||||
getExtendedSymbolSectionIndexTable(symbolTableSectionHeader);
|
||||
|
||||
ElfSymbolTable symbolTable = new ElfSymbolTable(reader, this,
|
||||
symbolTableSectionHeader, symbolTableSectionHeader.getOffset(),
|
||||
symbolTableSectionHeader.getAddress(), symbolTableSectionHeader.getSize(),
|
||||
symbolTableSectionHeader.getEntrySize(), stringTable, symbolSectionIndexTable,
|
||||
isDyanmic);
|
||||
ElfSymbolTable symbolTable =
|
||||
new ElfSymbolTable(reader, this, symbolTableSectionHeader,
|
||||
symbolTableSectionHeader.getOffset(), symbolTableSectionHeader.getAddress(),
|
||||
symbolTableSectionHeader.getSize(), symbolTableSectionHeader.getEntrySize(),
|
||||
stringTable, symbolSectionIndexTable, isDyanmic);
|
||||
symbolTableList.add(symbolTable);
|
||||
if (symbolTable.getAddressOffset() == dynamicSymbolTableAddr) {
|
||||
dynamicSymbolTable = symbolTable; // remember dynamic symbol table
|
||||
|
@ -976,8 +967,9 @@ public class ElfHeader implements StructConverter {
|
|||
}
|
||||
ElfProgramHeader hashTableLoadHeader = getProgramLoadHeaderContaining(hashTableAddr);
|
||||
if (hashTableLoadHeader == null) {
|
||||
errorConsumer.accept("Failed to locate DT_HASH, DT_GNU_HASH, or DT_GNU_XHASH in memory at 0x" +
|
||||
Long.toHexString(hashTableAddr));
|
||||
errorConsumer.accept(
|
||||
"Failed to locate DT_HASH, DT_GNU_HASH, or DT_GNU_XHASH in memory at 0x" +
|
||||
Long.toHexString(hashTableAddr));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1001,9 +993,8 @@ public class ElfHeader implements StructConverter {
|
|||
// 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.
|
||||
|
||||
return new ElfSymbolTable(reader, this, null, symbolTableOffset,
|
||||
tableAddr, tableEntrySize * symCount, tableEntrySize, dynamicStringTable, null,
|
||||
true);
|
||||
return new ElfSymbolTable(reader, this, null, symbolTableOffset, tableAddr,
|
||||
tableEntrySize * symCount, tableEntrySize, dynamicStringTable, null, true);
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
throw new AssertException(e);
|
||||
|
@ -1082,8 +1073,7 @@ public class ElfHeader implements StructConverter {
|
|||
}
|
||||
}
|
||||
|
||||
protected void parseSectionHeaders()
|
||||
throws IOException {
|
||||
protected void parseSectionHeaders() throws IOException {
|
||||
if (reader == 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);
|
||||
if (!missing && !providerContainsRegion(index, e_shentsize)) {
|
||||
int unreadCnt = e_shnum - i;
|
||||
errorConsumer.accept(
|
||||
unreadCnt + " of " + e_shnum +
|
||||
" section headers are truncated/missing from file");
|
||||
errorConsumer.accept(unreadCnt + " of " + e_shnum +
|
||||
" section headers are truncated/missing from file");
|
||||
missing = true;
|
||||
}
|
||||
reader.setPointerIndex(index);
|
||||
sectionHeaders[i] = new ElfSectionHeader(reader, this);
|
||||
sectionHeaders[i] = new ElfSectionHeader(reader.clone(index), this);
|
||||
if (sectionHeaders[i].getType() == ElfSectionHeaderConstants.SHT_SYMTAB_SHNDX) {
|
||||
hasExtendedSymbolSectionIndexTable = true;
|
||||
}
|
||||
|
@ -1123,21 +1111,18 @@ public class ElfHeader implements StructConverter {
|
|||
}
|
||||
}
|
||||
|
||||
private void parseProgramHeaders()
|
||||
throws IOException {
|
||||
private void parseProgramHeaders() throws IOException {
|
||||
boolean missing = false;
|
||||
programHeaders = new ElfProgramHeader[e_phnum];
|
||||
for (int i = 0; i < e_phnum; ++i) {
|
||||
long index = e_phoff + (i * e_phentsize);
|
||||
if (!missing && !providerContainsRegion(index, e_phentsize)) {
|
||||
int unreadCnt = e_phnum - i;
|
||||
errorConsumer.accept(
|
||||
unreadCnt + " of " + e_phnum +
|
||||
" program headers are truncated/missing from file");
|
||||
errorConsumer.accept(unreadCnt + " of " + e_phnum +
|
||||
" program headers are truncated/missing from file");
|
||||
missing = true;
|
||||
}
|
||||
reader.setPointerIndex(index);
|
||||
programHeaders[i] = new ElfProgramHeader(reader, this);
|
||||
programHeaders[i] = new ElfProgramHeader(reader.clone(index), this);
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
long minBase = -1;
|
||||
|
||||
int n = Math.min(e_phnum, MAX_HEADERS_TO_CHECK_FOR_IMAGEBASE);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
long index = e_phoff + (i * e_phentsize);
|
||||
if (!providerContainsRegion(index, e_phentsize)) {
|
||||
break;
|
||||
}
|
||||
reader.setPointerIndex(index);
|
||||
try {
|
||||
int headerType = reader.peekNextInt();
|
||||
int headerType = reader.readInt(index);
|
||||
if (headerType == ElfProgramHeaderConstants.PT_LOAD) {
|
||||
ElfProgramHeader header = new ElfProgramHeader(reader, this);
|
||||
ElfProgramHeader header = new ElfProgramHeader(reader.clone(index), this);
|
||||
minBase = getMinBase(header.getVirtualAddress(), minBase);
|
||||
}
|
||||
}
|
||||
|
@ -1979,100 +1962,4 @@ public class ElfHeader implements StructConverter {
|
|||
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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.util.bin.format.elf;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
|
@ -66,35 +67,31 @@ import ghidra.util.StringUtilities;
|
|||
public class ElfProgramHeader
|
||||
implements StructConverter, Comparable<ElfProgramHeader>, MemoryLoadable {
|
||||
|
||||
protected ElfHeader header;
|
||||
protected final ElfHeader header;
|
||||
|
||||
private int p_type;
|
||||
private int p_flags;
|
||||
private long p_offset;
|
||||
private long p_vaddr;
|
||||
private long p_paddr;
|
||||
private long p_filesz;
|
||||
private long p_memsz;
|
||||
private long p_align;
|
||||
private final int p_type;
|
||||
private final int p_flags;
|
||||
private long p_offset; // may get altered after instantiation
|
||||
private final long p_vaddr;
|
||||
private final long p_paddr;
|
||||
private final long p_filesz;
|
||||
private final long p_memsz;
|
||||
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.reader = reader;
|
||||
|
||||
if (header.is32Bit()) {
|
||||
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()) {
|
||||
if (header.is64Bit()) {
|
||||
p_type = reader.readNextInt();
|
||||
p_flags = reader.readNextInt();
|
||||
p_offset = reader.readNextLong();
|
||||
|
@ -104,6 +101,16 @@ public class ElfProgramHeader
|
|||
p_memsz = 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) {
|
||||
//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
|
||||
|
@ -431,9 +422,6 @@ public class ElfProgramHeader
|
|||
return typeEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(ElfProgramHeader that) {
|
||||
//sort the headers putting 0xffffffff (new guys)
|
||||
|
@ -457,7 +445,7 @@ public class ElfProgramHeader
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) ((31 * p_offset) + (p_offset >>> 32));
|
||||
return Objects.hash(p_offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -466,8 +454,8 @@ public class ElfProgramHeader
|
|||
return false;
|
||||
}
|
||||
ElfProgramHeader other = (ElfProgramHeader) obj;
|
||||
return reader == other.reader && p_type == other.p_type && p_flags == other.p_flags &&
|
||||
p_offset == other.p_offset && p_vaddr == other.p_vaddr && p_paddr == other.p_paddr &&
|
||||
p_filesz == other.p_filesz && p_memsz == other.p_memsz && p_align == other.p_align;
|
||||
return p_type == other.p_type && p_flags == other.p_flags && p_offset == other.p_offset &&
|
||||
p_vaddr == other.p_vaddr && p_paddr == other.p_paddr && p_filesz == other.p_filesz &&
|
||||
p_memsz == other.p_memsz && p_align == other.p_align;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,8 +100,8 @@ public class ElfRelocation implements StructConverter {
|
|||
* @return ELF relocation object
|
||||
* @throws IOException if an IO or parse error occurs
|
||||
*/
|
||||
static ElfRelocation createElfRelocation(BinaryReader reader,
|
||||
ElfHeader elfHeader, int relocationIndex, boolean withAddend) throws IOException {
|
||||
static ElfRelocation createElfRelocation(BinaryReader reader, ElfHeader elfHeader,
|
||||
int relocationIndex, boolean withAddend) throws IOException {
|
||||
Class<? extends ElfRelocation> elfRelocationClazz = getElfRelocationClass(elfHeader);
|
||||
ElfRelocation elfRelocation = getInstance(elfRelocationClazz);
|
||||
elfRelocation.initElfRelocation(reader, elfHeader, relocationIndex, withAddend);
|
||||
|
@ -120,9 +120,8 @@ public class ElfRelocation implements StructConverter {
|
|||
* @return ELF relocation object
|
||||
* @throws IOException if an IO or parse error occurs
|
||||
*/
|
||||
static ElfRelocation createElfRelocation(ElfHeader elfHeader,
|
||||
int relocationIndex, boolean withAddend, long r_offset, long r_info, long r_addend)
|
||||
throws IOException {
|
||||
static ElfRelocation createElfRelocation(ElfHeader elfHeader, int relocationIndex,
|
||||
boolean withAddend, long r_offset, long r_info, long r_addend) throws IOException {
|
||||
Class<? extends ElfRelocation> elfRelocationClazz = getElfRelocationClass(elfHeader);
|
||||
ElfRelocation elfRelocation = getInstance(elfRelocationClazz);
|
||||
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 {
|
||||
if (is32bit) {
|
||||
this.r_offset = Integer.toUnsignedLong(reader.readNextInt());
|
||||
this.r_info = Integer.toUnsignedLong(reader.readNextInt());
|
||||
this.r_offset = reader.readNextUnsignedInt();
|
||||
this.r_info = reader.readNextUnsignedInt();
|
||||
if (hasAddend) {
|
||||
r_addend = reader.readNextInt();
|
||||
}
|
||||
|
|
|
@ -32,27 +32,27 @@ public class ElfRelocationTable implements ElfFileSection {
|
|||
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 long fileOffset;
|
||||
private long addrOffset;
|
||||
private long length;
|
||||
private long entrySize;
|
||||
private final ElfSectionHeader relocTableSection; // may be null
|
||||
private final long fileOffset;
|
||||
private final long addrOffset;
|
||||
private final long length;
|
||||
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
|
||||
* @param reader byte provider reader
|
||||
* @param reader byte provider reader (reader is not retained and position is unaffected)
|
||||
* @param header elf header
|
||||
* @param relocTableSection relocation table section header or null if associated with a dynamic table entry
|
||||
* @param fileOffset relocation table file offset
|
||||
|
@ -70,34 +70,30 @@ public class ElfRelocationTable implements ElfFileSection {
|
|||
long entrySize, boolean addendTypeReloc, ElfSymbolTable symbolTable,
|
||||
ElfSectionHeader sectionToBeRelocated, TableFormat format) throws IOException {
|
||||
|
||||
this.elfHeader = header;
|
||||
this.relocTableSection = relocTableSection;
|
||||
this.fileOffset = fileOffset;
|
||||
this.addrOffset = addrOffset;
|
||||
this.length = length;
|
||||
this.entrySize = entrySize;
|
||||
this.entrySize = (format == TableFormat.DEFAULT && entrySize <= 0)
|
||||
? ElfRelocation.getStandardRelocationEntrySize(header.is64Bit(), addendTypeReloc)
|
||||
: entrySize;
|
||||
this.addendTypeReloc = addendTypeReloc;
|
||||
this.elfHeader = header;
|
||||
this.format = format;
|
||||
|
||||
this.sectionToBeRelocated = sectionToBeRelocated;
|
||||
this.symbolTable = symbolTable;
|
||||
|
||||
long ptr = reader.getPointerIndex();
|
||||
reader.setPointerIndex(fileOffset);
|
||||
|
||||
BinaryReader relocReader = reader.clone(fileOffset);
|
||||
List<ElfRelocation> relocList;
|
||||
if (format == TableFormat.RELR) {
|
||||
relocList = parseRelrRelocations(reader);
|
||||
relocList = parseRelrRelocations(relocReader);
|
||||
}
|
||||
else if (format == TableFormat.ANDROID) {
|
||||
relocList = parseAndroidRelocations(reader);
|
||||
relocList = parseAndroidRelocations(relocReader);
|
||||
}
|
||||
else {
|
||||
relocList = parseStandardRelocations(reader);
|
||||
relocList = parseStandardRelocations(relocReader);
|
||||
}
|
||||
|
||||
reader.setPointerIndex(ptr);
|
||||
|
||||
relocs = new ElfRelocation[relocList.size()];
|
||||
relocList.toArray(relocs);
|
||||
}
|
||||
|
@ -117,13 +113,8 @@ public class ElfRelocationTable implements ElfFileSection {
|
|||
return false;
|
||||
}
|
||||
|
||||
private List<ElfRelocation> parseStandardRelocations(BinaryReader reader)
|
||||
throws IOException {
|
||||
|
||||
private List<ElfRelocation> parseStandardRelocations(BinaryReader reader) throws IOException {
|
||||
List<ElfRelocation> relocations = new ArrayList<>();
|
||||
if (entrySize <= 0) {
|
||||
entrySize = ElfRelocation.getStandardRelocationEntrySize(elfHeader.is64Bit(), addendTypeReloc);
|
||||
}
|
||||
int nRelocs = (int) (length / entrySize);
|
||||
for (int relocationIndex = 0; relocationIndex < nRelocs; ++relocationIndex) {
|
||||
relocations.add(ElfRelocation.createElfRelocation(reader, elfHeader, relocationIndex,
|
||||
|
@ -148,8 +139,8 @@ public class ElfRelocationTable implements ElfFileSection {
|
|||
while (entry != 0) {
|
||||
entry >>>= 1;
|
||||
if ((entry & 1) != 0) {
|
||||
relocList.add(ElfRelocation.createElfRelocation(elfHeader,
|
||||
relocList.size(), addendTypeReloc, offset, 0, 0));
|
||||
relocList.add(ElfRelocation.createElfRelocation(elfHeader, relocList.size(),
|
||||
addendTypeReloc, offset, 0, 0));
|
||||
}
|
||||
offset += entrySize;
|
||||
}
|
||||
|
@ -157,8 +148,7 @@ public class ElfRelocationTable implements ElfFileSection {
|
|||
return baseOffset + (nBits * entrySize);
|
||||
}
|
||||
|
||||
private List<ElfRelocation> parseRelrRelocations(BinaryReader reader)
|
||||
throws IOException {
|
||||
private List<ElfRelocation> parseRelrRelocations(BinaryReader reader) throws IOException {
|
||||
|
||||
// NOTE: Current implementation supports an entrySize of 8 or 4. This could be
|
||||
// made more flexable if needed (applies to ElfRelrRelocationTableDataType as well)
|
||||
|
@ -183,8 +173,7 @@ public class ElfRelocationTable implements ElfFileSection {
|
|||
return relocList;
|
||||
}
|
||||
|
||||
private List<ElfRelocation> parseAndroidRelocations(BinaryReader reader)
|
||||
throws IOException {
|
||||
private List<ElfRelocation> parseAndroidRelocations(BinaryReader reader) throws IOException {
|
||||
|
||||
String identifier = reader.readNextAsciiString(4);
|
||||
if (!"APS2".equals(identifier)) {
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.util.bin.format.elf;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
|
@ -25,8 +26,6 @@ import ghidra.app.util.bin.*;
|
|||
import ghidra.app.util.bin.format.MemoryLoadable;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.StringUtilities;
|
||||
|
||||
|
@ -73,58 +72,63 @@ import ghidra.util.StringUtilities;
|
|||
|
||||
public class ElfSectionHeader implements StructConverter, MemoryLoadable {
|
||||
|
||||
private int sh_name;
|
||||
private int sh_type;
|
||||
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 final BinaryReader reader;
|
||||
private final ElfHeader header;
|
||||
|
||||
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;
|
||||
private byte[] data;
|
||||
private boolean modified = false;
|
||||
private boolean bytesChanged = false;
|
||||
private String name; // delayed initialization
|
||||
|
||||
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 {
|
||||
|
||||
this.reader = reader;
|
||||
this.header = header;
|
||||
|
||||
sh_name = reader.readNextInt();
|
||||
sh_type = reader.readNextInt();
|
||||
|
||||
if (header.is32Bit()) {
|
||||
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()) {
|
||||
if (header.is64Bit()) {
|
||||
sh_flags = reader.readNextLong();
|
||||
sh_addr = reader.readNextLong();
|
||||
sh_offset = 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_info = reader.readNextInt();
|
||||
|
||||
if (header.is32Bit()) {
|
||||
sh_addralign = Integer.toUnsignedLong(reader.readNextInt());
|
||||
sh_entsize = Integer.toUnsignedLong(reader.readNextInt());
|
||||
}
|
||||
else if (header.is64Bit()) {
|
||||
if (header.is64Bit()) {
|
||||
sh_addralign = 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) {
|
||||
compressedHeader = readCompressedSectionHeader();
|
||||
|
@ -148,7 +152,6 @@ public class ElfSectionHeader implements StructConverter, MemoryLoadable {
|
|||
}
|
||||
catch (IOException e) {
|
||||
Msg.warn(this, "Error reading compressed section information: " + e);
|
||||
Msg.debug(this, "Error reading compressed section information", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -159,56 +162,6 @@ public class ElfSectionHeader implements StructConverter, MemoryLoadable {
|
|||
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
|
||||
|
@ -538,24 +491,6 @@ public class ElfSectionHeader implements StructConverter, MemoryLoadable {
|
|||
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.
|
||||
* @param addr the new start address of this section
|
||||
|
@ -626,7 +561,7 @@ public class ElfSectionHeader implements StructConverter, MemoryLoadable {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) ((17 * sh_offset) + (sh_offset >>> 32));
|
||||
return Objects.hash(sh_offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -635,11 +570,10 @@ public class ElfSectionHeader implements StructConverter, MemoryLoadable {
|
|||
return false;
|
||||
}
|
||||
ElfSectionHeader other = (ElfSectionHeader) obj;
|
||||
return reader == other.reader && sh_name == other.sh_name && sh_type == other.sh_type &&
|
||||
sh_flags == other.sh_flags && sh_addr == other.sh_addr &&
|
||||
sh_offset == other.sh_offset && sh_size == other.sh_size && sh_link == other.sh_link &&
|
||||
sh_info == other.sh_info && sh_addralign == other.sh_addralign &&
|
||||
sh_entsize == other.sh_entsize;
|
||||
return sh_name == other.sh_name && sh_type == other.sh_type && sh_flags == other.sh_flags &&
|
||||
sh_addr == other.sh_addr && sh_offset == other.sh_offset && sh_size == other.sh_size &&
|
||||
sh_link == other.sh_link && sh_info == other.sh_info &&
|
||||
sh_addralign == other.sh_addralign && sh_entsize == other.sh_entsize;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -138,27 +138,27 @@ public class ElfSectionHeaderConstants {
|
|||
// Section Header Flag Bits
|
||||
|
||||
/**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*/
|
||||
public static final int SHF_ALLOC = (1 << 1);
|
||||
public static final int SHF_ALLOC = 0x2;
|
||||
/**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*/
|
||||
public static final int SHF_MERGE = (1 << 4);
|
||||
public static final int SHF_MERGE = 0x10;
|
||||
/**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*/
|
||||
public static final int SHF_INFO_LINK = (1 << 6);
|
||||
public static final int SHF_INFO_LINK = 0x40;
|
||||
/**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*/
|
||||
public static final int SHF_OS_NONCONFORMING = (1 << 8);
|
||||
public static final int SHF_OS_NONCONFORMING = 0x100;
|
||||
/**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.*/
|
||||
public static final int SHF_TLS = (1 << 10);
|
||||
public static final int SHF_TLS = 0x400;
|
||||
/**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.*/
|
||||
public static final int SHF_EXCLUDE = 0x80000000;
|
||||
/**The section contains OS-specific data.*/
|
||||
|
|
|
@ -23,12 +23,12 @@ import ghidra.util.exception.DuplicateNameException;
|
|||
|
||||
public class ElfStringTable implements ElfFileSection {
|
||||
|
||||
private ElfHeader header;
|
||||
private final ElfHeader header;
|
||||
|
||||
private ElfSectionHeader stringTableSection; // may be null
|
||||
private long fileOffset;
|
||||
private long addrOffset;
|
||||
private long length;
|
||||
private final ElfSectionHeader stringTableSection; // may be null
|
||||
private final long fileOffset;
|
||||
private final long addrOffset;
|
||||
private final long length;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param reader byte reader
|
||||
* @param reader byte reader (position remains unchanged)
|
||||
* @param stringOffset table relative string offset
|
||||
* @return string or null on error
|
||||
*/
|
||||
|
|
|
@ -92,14 +92,14 @@ public class ElfSymbol {
|
|||
public static final byte STV_PROTECTED = 3;
|
||||
|
||||
private ElfSymbolTable symbolTable;
|
||||
private int symbolTableIndex;
|
||||
private final int symbolTableIndex;
|
||||
|
||||
private int st_name;
|
||||
private long st_value;
|
||||
private long st_size;
|
||||
private byte st_info;
|
||||
private byte st_other;
|
||||
private short st_shndx;
|
||||
private final int st_name;
|
||||
private final long st_value;
|
||||
private final long st_size;
|
||||
private final byte st_info;
|
||||
private final byte st_other;
|
||||
private final short st_shndx;
|
||||
|
||||
private String nameAsString;
|
||||
|
||||
|
@ -107,28 +107,36 @@ public class ElfSymbol {
|
|||
* Construct a new special null symbol which corresponds to symbol index 0.
|
||||
*/
|
||||
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.
|
||||
* Warning! the routine initSymbolName() must be called on the symbol later
|
||||
* 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 symbolTable symbol table to associate the symbol to
|
||||
* @param header else header
|
||||
* @throws IOException if an issue with reading occurs
|
||||
* @param header ELF header
|
||||
* @throws IOException if an IO error occurs during parse
|
||||
*/
|
||||
public ElfSymbol(BinaryReader reader, int symbolIndex,
|
||||
ElfSymbolTable symbolTable, ElfHeader header) throws IOException {
|
||||
public ElfSymbol(BinaryReader reader, int symbolIndex, ElfSymbolTable symbolTable,
|
||||
ElfHeader header) throws IOException {
|
||||
this.symbolTable = symbolTable;
|
||||
this.symbolTableIndex = symbolIndex;
|
||||
|
||||
if (header.is32Bit()) {
|
||||
st_name = reader.readNextInt();
|
||||
st_value = Integer.toUnsignedLong(reader.readNextInt());
|
||||
st_size = Integer.toUnsignedLong(reader.readNextInt());
|
||||
st_value = reader.readNextUnsignedInt();
|
||||
st_size = reader.readNextUnsignedInt();
|
||||
st_info = reader.readNextByte();
|
||||
st_other = reader.readNextByte();
|
||||
st_shndx = reader.readNextShort();
|
||||
|
@ -171,7 +179,7 @@ public class ElfSymbol {
|
|||
* at the same time the reading buffer will jump around and significantly
|
||||
* degrade reading performance.
|
||||
*
|
||||
* @param reader to read from
|
||||
* @param reader to read from (position remains unchanged)
|
||||
* @param stringTable stringTable to initialize symbol name
|
||||
*/
|
||||
public void initSymbolName(BinaryReader reader, ElfStringTable stringTable) {
|
||||
|
@ -492,8 +500,8 @@ public class ElfSymbol {
|
|||
return nameAsString + " - " + "st_value: 0x" + Long.toHexString(st_value) + " - " +
|
||||
"st_size: 0x" + Long.toHexString(st_size) + " - " + "st_info: 0x" +
|
||||
Integer.toHexString(Byte.toUnsignedInt(st_info)) + " - " + "st_other: 0x" +
|
||||
Integer.toHexString(Byte.toUnsignedInt(st_other)) +
|
||||
" - " + "st_shndx: 0x" + Integer.toHexString(Short.toUnsignedInt(st_shndx));
|
||||
Integer.toHexString(Byte.toUnsignedInt(st_other)) + " - " + "st_shndx: 0x" +
|
||||
Integer.toHexString(Short.toUnsignedInt(st_shndx));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,23 +29,23 @@ import ghidra.util.exception.DuplicateNameException;
|
|||
*/
|
||||
public class ElfSymbolTable implements ElfFileSection {
|
||||
|
||||
private ElfStringTable stringTable;
|
||||
private ElfSectionHeader symbolTableSection; // may be null
|
||||
private int[] symbolSectionIndexTable;
|
||||
private long fileOffset;
|
||||
private long addrOffset;
|
||||
private long length;
|
||||
private long entrySize;
|
||||
private int symbolCount;
|
||||
private final ElfStringTable stringTable;
|
||||
private final ElfSectionHeader symbolTableSection; // may be null
|
||||
private final int[] symbolSectionIndexTable;
|
||||
private final long fileOffset;
|
||||
private final long addrOffset;
|
||||
private final long length;
|
||||
private final long entrySize;
|
||||
private final int symbolCount;
|
||||
|
||||
private boolean is32bit;
|
||||
private boolean isDynamic;
|
||||
private final boolean is32bit;
|
||||
private final boolean isDynamic;
|
||||
|
||||
private ElfSymbol[] symbols;
|
||||
private final ElfSymbol[] symbols;
|
||||
|
||||
/**
|
||||
* 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 symbolTableSection string table section header or null if associated with a dynamic table entry
|
||||
* @param fileOffset symbol table file offset
|
||||
|
@ -74,36 +74,33 @@ public class ElfSymbolTable implements ElfFileSection {
|
|||
this.symbolSectionIndexTable = symbolSectionIndexTable;
|
||||
this.isDynamic = isDynamic;
|
||||
|
||||
long ptr = reader.getPointerIndex();
|
||||
reader.setPointerIndex(fileOffset);
|
||||
BinaryReader symTableReader = reader.clone(fileOffset);
|
||||
|
||||
List<ElfSymbol> symbolList = new ArrayList<>();
|
||||
symbolCount = (int) (length / entrySize);
|
||||
|
||||
long entryPos = reader.getPointerIndex();
|
||||
|
||||
// load the all the symbol entries first, don't initialize the string name
|
||||
// that will be done later to help localize memory access
|
||||
long entryPos = fileOffset;
|
||||
for (int i = 0; i < symbolCount; i++) {
|
||||
// Reposition reader to start of symbol element since ElfSymbol object
|
||||
// may not consume all symbol element data
|
||||
reader.setPointerIndex(entryPos);
|
||||
ElfSymbol sym = new ElfSymbol(reader, i, this, header);
|
||||
symTableReader.setPointerIndex(entryPos);
|
||||
ElfSymbol sym = new ElfSymbol(symTableReader, i, this, header);
|
||||
symbolList.add(sym);
|
||||
entryPos += entrySize;
|
||||
}
|
||||
|
||||
// sort the entries by the index in the string table, so don't jump around reading
|
||||
List<ElfSymbol> sortedList = symbolList.stream().sorted(
|
||||
(o1, o2) -> Integer.compare(o1.getName(), o2.getName())).collect(Collectors.toList());
|
||||
List<ElfSymbol> sortedList = symbolList.stream()
|
||||
.sorted((o1, o2) -> Integer.compare(o1.getName(), o2.getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// initialize the Symbol string names from string table
|
||||
for (ElfSymbol sym : sortedList) {
|
||||
sym.initSymbolName(reader, stringTable);
|
||||
sym.initSymbolName(symTableReader, stringTable);
|
||||
}
|
||||
|
||||
reader.setPointerIndex(ptr);
|
||||
|
||||
symbols = new ElfSymbol[symbolList.size()];
|
||||
symbolList.toArray(symbols);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue