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
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.*/
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue