mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-1110 Refactor ElfDefaultGotPltMarkup.processDynamicPLTGOT implementation, Correct duplicate ELF relocation table processing, and other minor ELF cleanup
This commit is contained in:
parent
3c1e51d0c0
commit
0a24532bf7
9 changed files with 346 additions and 130 deletions
|
@ -512,18 +512,4 @@ public interface ElfConstants {
|
||||||
/** used by NetBSD/avr32 - AVR 32-bit */
|
/** used by NetBSD/avr32 - AVR 32-bit */
|
||||||
public static final short EM_AVR32_unofficial = 0x18ad;
|
public static final short EM_AVR32_unofficial = 0x18ad;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The size in bytes of the entry in the program
|
|
||||||
* location table (PLT).
|
|
||||||
*/
|
|
||||||
public static final int PLT_ENTRY_SIZE = 0x10;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The size in bytes of the entry in the program
|
|
||||||
* location table (PLT) in ARM files.
|
|
||||||
*/
|
|
||||||
//public static final int PLT_ENTRY_SIZE_ARM = 0x12;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.elf;
|
package ghidra.app.util.bin.format.elf;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
import ghidra.app.cmd.refs.RemoveReferenceCmd;
|
||||||
import ghidra.framework.store.LockException;
|
|
||||||
import ghidra.program.disassemble.Disassembler;
|
import ghidra.program.disassemble.Disassembler;
|
||||||
import ghidra.program.disassemble.DisassemblerMessageListener;
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
@ -38,6 +38,9 @@ import ghidra.util.task.TaskMonitor;
|
||||||
*/
|
*/
|
||||||
public class ElfDefaultGotPltMarkup {
|
public class ElfDefaultGotPltMarkup {
|
||||||
|
|
||||||
|
// When PLT head is known and named sections are missing this label will be placed at head of PLT
|
||||||
|
private static final String PLT_HEAD_SYMBOL_NAME = "__PLT_HEAD";
|
||||||
|
|
||||||
private ElfLoadHelper elfLoadHelper;
|
private ElfLoadHelper elfLoadHelper;
|
||||||
private ElfHeader elf;
|
private ElfHeader elf;
|
||||||
private Program program;
|
private Program program;
|
||||||
|
@ -58,7 +61,7 @@ public class ElfDefaultGotPltMarkup {
|
||||||
|
|
||||||
public void process(TaskMonitor monitor) throws CancelledException {
|
public void process(TaskMonitor monitor) throws CancelledException {
|
||||||
if (elf.e_shnum() == 0) {
|
if (elf.e_shnum() == 0) {
|
||||||
processDynamicPLTGOT(monitor);
|
processDynamicPLTGOT(ElfDynamicType.DT_PLTGOT, ElfDynamicType.DT_JMPREL, monitor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
processGOTSections(monitor);
|
processGOTSections(monitor);
|
||||||
|
@ -87,30 +90,55 @@ public class ElfDefaultGotPltMarkup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class PltGotSymbol implements Comparable<PltGotSymbol> {
|
||||||
|
final ElfSymbol elfSymbol;
|
||||||
|
final long offset;
|
||||||
|
|
||||||
|
PltGotSymbol(ElfSymbol elfSymbol, long offset) {
|
||||||
|
this.elfSymbol = elfSymbol;
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(PltGotSymbol o) {
|
||||||
|
return Long.compareUnsigned(offset, o.offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When scanning PLT for symbols the min/max entry size are used to control the search
|
||||||
|
private static final int MAX_SUPPORTED_PLT_ENTRY_SIZE = 32;
|
||||||
|
private static final int MIN_SUPPORTED_PLT_ENTRY_SIZE = 8;
|
||||||
|
|
||||||
|
// When scanning PLT for symbol spacing this is the threashold used to stop the search
|
||||||
|
// when the same spacing size is detected in an attempt to identify the PLT entry size
|
||||||
|
private static final int PLT_SYMBOL_SAMPLE_COUNT_THRESHOLD = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process GOT table specified by Dynamic Program Header (DT_PLTGOT).
|
* Process GOT and associated PLT based upon specified dynamic table entries.
|
||||||
* Entry count determined by corresponding relocation table identified by
|
* The primary goal is to identify the bounds of the GOT and PLT and process
|
||||||
* the dynamic table entry DT_JMPREL.
|
* any external symbols which may be defined within the PLT. Processing of PLT
|
||||||
|
* is only critical if it contains external symbols which must be processed, otherwise
|
||||||
|
* they will likely resolve adequately during subsequent analysis.
|
||||||
|
* @param pltGotType dynamic type for dynamic PLTGOT lookup (identifies dynamic PLTGOT)
|
||||||
|
* @param pltGotRelType dynamic type for associated dynamic JMPREL lookup (identifies dynamic PLTGOT relocation table)
|
||||||
* @param monitor task monitor
|
* @param monitor task monitor
|
||||||
* @throws CancelledException thrown if task cancelled
|
* @throws CancelledException thrown if task cancelled
|
||||||
*/
|
*/
|
||||||
private void processDynamicPLTGOT(TaskMonitor monitor) throws CancelledException {
|
private void processDynamicPLTGOT(ElfDynamicType pltGotType, ElfDynamicType pltGotRelType,
|
||||||
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
ElfDynamicTable dynamicTable = elf.getDynamicTable();
|
ElfDynamicTable dynamicTable = elf.getDynamicTable();
|
||||||
if (dynamicTable == null || !dynamicTable.containsDynamicValue(ElfDynamicType.DT_PLTGOT) ||
|
if (dynamicTable == null || !dynamicTable.containsDynamicValue(pltGotType) ||
|
||||||
!dynamicTable.containsDynamicValue(ElfDynamicType.DT_JMPREL)) {
|
!dynamicTable.containsDynamicValue(pltGotRelType)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: there may be other relocation table affecting the GOT
|
|
||||||
// corresponding to DT_PLTGOT
|
|
||||||
|
|
||||||
AddressSpace defaultSpace = program.getAddressFactory().getDefaultAddressSpace();
|
AddressSpace defaultSpace = program.getAddressFactory().getDefaultAddressSpace();
|
||||||
long imageBaseAdj = elfLoadHelper.getImageBaseWordAdjustmentOffset();
|
long imageBaseAdj = elfLoadHelper.getImageBaseWordAdjustmentOffset();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
long relocTableAddr =
|
long relocTableAddr =
|
||||||
elf.adjustAddressForPrelink(dynamicTable.getDynamicValue(ElfDynamicType.DT_JMPREL));
|
elf.adjustAddressForPrelink(dynamicTable.getDynamicValue(pltGotRelType));
|
||||||
|
|
||||||
ElfProgramHeader relocTableLoadHeader =
|
ElfProgramHeader relocTableLoadHeader =
|
||||||
elf.getProgramLoadHeaderContaining(relocTableAddr);
|
elf.getProgramLoadHeaderContaining(relocTableAddr);
|
||||||
|
@ -123,44 +151,199 @@ public class ElfDefaultGotPltMarkup {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// External dynamic symbol entries in the PLTGOT, if any, will be placed
|
// External dynamic symbol entries in the GOT, if any, will be placed
|
||||||
// after any local symbol entries.
|
// after any local symbol entries. Local entries are assumed to have original
|
||||||
|
// bytes of zero, whereas non-local entries will refer to the PLT
|
||||||
|
|
||||||
// While DT_PLTGOT identifies the start of the PLTGOT it does not
|
// While the dynamic value for pltGotType (e.g., DT_PLTGOT) identifies the start of
|
||||||
// specify its length. If there are dynamic non-local entries in the
|
// dynamic GOT table it does not specify its length. The associated relocation
|
||||||
// PLTGOT they should have relocation entries in the table identified
|
// table, identified by the dynamic value for pltGotRelType, will have a relocation
|
||||||
// by DT_JMPREL. It is important to note that this relocation table
|
// record for each PLT entry linked via the GOT. The number of relocations matches
|
||||||
// can include entries which affect other processor-specific PLTGOT
|
// the number of PLT entries and the one with the greatest offset correspionds
|
||||||
// tables (e.g., MIPS_PLTGOT) so we must attempt to isolate the
|
// to the last GOT entry. Unfortuntely, the length of each PLT entry and initial
|
||||||
// entries which correspond to DT_PLTGOT.
|
// PLT head is unknown. If the binary has not placed external symbols within the PLT
|
||||||
|
// processing and disassembly of the PLT may be skipped.
|
||||||
// WARNING: This implementation makes a potentially bad assumption that
|
|
||||||
// the last relocation entry will identify the endof the PLTGOT if its
|
|
||||||
// offset is beyond the start of the PLTGOT. This assumption could
|
|
||||||
// easily be violated by a processor-specific PLTGOT which falls after
|
|
||||||
// the standard PLTGOT in memory and shares the same relocation table.
|
|
||||||
|
|
||||||
long pltgot = elf.adjustAddressForPrelink(
|
long pltgot = elf.adjustAddressForPrelink(
|
||||||
dynamicTable.getDynamicValue(ElfDynamicType.DT_PLTGOT));
|
dynamicTable.getDynamicValue(pltGotType));
|
||||||
|
Address gotStart = defaultSpace.getAddress(pltgot + imageBaseAdj);
|
||||||
|
|
||||||
ElfRelocation[] relocations = relocationTable.getRelocations();
|
ElfRelocation[] relocations = relocationTable.getRelocations();
|
||||||
|
ElfSymbolTable associatedSymbolTable = relocationTable.getAssociatedSymbolTable();
|
||||||
long lastGotOffset = relocations[relocations.length - 1].getOffset();
|
if (associatedSymbolTable == null) {
|
||||||
if (lastGotOffset < pltgot) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Address gotStart = defaultSpace.getAddress(pltgot + imageBaseAdj);
|
// Create ordered list of PLTGOT symbols based upon offset with GOT.
|
||||||
Address gotEnd = defaultSpace.getAddress(lastGotOffset + imageBaseAdj);
|
// It assumed that the PLT entry sequence will match this list.
|
||||||
|
ElfSymbol[] symbols = associatedSymbolTable.getSymbols();
|
||||||
|
List<PltGotSymbol> pltGotSymbols = new ArrayList<>();
|
||||||
|
for (ElfRelocation reloc : relocations) {
|
||||||
|
pltGotSymbols
|
||||||
|
.add(new PltGotSymbol(symbols[reloc.getSymbolIndex()], reloc.getOffset()));
|
||||||
|
}
|
||||||
|
Collections.sort(pltGotSymbols);
|
||||||
|
|
||||||
|
// Identify end of GOT table based upon relocation offsets
|
||||||
|
long maxGotOffset = pltGotSymbols.get(pltGotSymbols.size() - 1).offset;
|
||||||
|
Address gotEnd = defaultSpace.getAddress(maxGotOffset + imageBaseAdj);
|
||||||
|
|
||||||
processGOT(gotStart, gotEnd, monitor);
|
processGOT(gotStart, gotEnd, monitor);
|
||||||
processDynamicPLT(gotStart, gotEnd, monitor);
|
|
||||||
|
//
|
||||||
|
// Examine the first two GOT entries which correspond to the relocations (i.e., pltGotSymbols).
|
||||||
|
// An adjusted address from the original bytes is computed. These will point into the PLT.
|
||||||
|
// These two pointers will either refer to the same address (i.e., PLT head) or different
|
||||||
|
// addresses which correspond to the first two PLT entries. While likely offcut into each PLT
|
||||||
|
// entry, the differing PLT addresses can be used to identify the PLT entry size/spacing but
|
||||||
|
// not the top of PLT. If symbols are present within the PLT for each entry, they may
|
||||||
|
// be used to identify the PLT entry size/spacing and will be converted to external symbols.
|
||||||
|
//
|
||||||
|
|
||||||
|
long pltEntryCount = pltGotSymbols.size();
|
||||||
|
|
||||||
|
// Get original bytes, converted to addresses, for first two PLT/GOT symbols
|
||||||
|
Address pltAddr1 = null;
|
||||||
|
Address pltAddr2 = null;
|
||||||
|
for (PltGotSymbol pltGotSym : pltGotSymbols) {
|
||||||
|
Address gotEntryAddr = defaultSpace.getAddress(pltGotSym.offset + imageBaseAdj);
|
||||||
|
long originalGotEntry = elfLoadHelper.getOriginalValue(gotEntryAddr, true);
|
||||||
|
if (originalGotEntry == 0) {
|
||||||
|
return; // unexpected original bytes for PLTGOT entry - skip PLT processing
|
||||||
|
}
|
||||||
|
if (pltAddr1 == null) {
|
||||||
|
pltAddr1 = defaultSpace.getAddress(originalGotEntry + imageBaseAdj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pltAddr2 = defaultSpace.getAddress(originalGotEntry + imageBaseAdj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pltAddr2 == null) {
|
||||||
|
return; // unable to find two GOT entries which refer to PLT - skip PLT processing
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: This approach assumes that all PLT entries have the same structure (i.e., instruction sequence)
|
||||||
|
long pltSpacing = pltAddr2.subtract(pltAddr1);
|
||||||
|
if (pltSpacing < 0 || pltSpacing > MAX_SUPPORTED_PLT_ENTRY_SIZE ||
|
||||||
|
(pltSpacing % 2) != 0) {
|
||||||
|
return; // unsupported PLT entry size - skip PLT processing
|
||||||
|
}
|
||||||
|
|
||||||
|
Address minSymbolSearchAddress;
|
||||||
|
long symbolSearchSpacing; // nominal PLT entry size for computing maxSymbolSearchAddress
|
||||||
|
|
||||||
|
Address firstPltEntryAddr = null; // may be offcut within first PLT entry
|
||||||
|
|
||||||
|
if (pltSpacing == 0) { // Entries have same original bytes which refer to PLT head
|
||||||
|
Function pltHeadFunc = elfLoadHelper.createOneByteFunction(null, pltAddr1, false);
|
||||||
|
if (pltHeadFunc.getSymbol().getSource() == SourceType.DEFAULT) {
|
||||||
|
try {
|
||||||
|
pltHeadFunc.setName(PLT_HEAD_SYMBOL_NAME, SourceType.ANALYSIS);
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException | InvalidInputException e) {
|
||||||
|
// Ignore - unexpected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PLT spacing is not known. pltAddr1 is PLT head
|
||||||
|
minSymbolSearchAddress = pltAddr1.next();
|
||||||
|
|
||||||
|
// Use conservative PLT entry size when computing address limit for PLT symbol search.
|
||||||
|
// For a PLT with an actual entry size of 16 this will reduce the scan to less than half
|
||||||
|
// of the PLT. This should only present an issue for very small PLTs or those
|
||||||
|
// with sparsely placed symbols.
|
||||||
|
symbolSearchSpacing = MIN_SUPPORTED_PLT_ENTRY_SIZE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// PLT spacing is known, but start of entry and head is not known. pltAddr1 points to middle of first PLT entry (not head).
|
||||||
|
firstPltEntryAddr = pltAddr1;
|
||||||
|
minSymbolSearchAddress = pltAddr1.subtract(pltSpacing - 1); // try to avoid picking up symbol which may be at head
|
||||||
|
symbolSearchSpacing = pltSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to find symbols located within the PLT.
|
||||||
|
Address maxSymbolSearchAddress =
|
||||||
|
minSymbolSearchAddress.add(pltEntryCount * symbolSearchSpacing);
|
||||||
|
|
||||||
|
// Scan symbols within PLT; helps to identify start of first entry and PLT entry size/spacing if unknown
|
||||||
|
Symbol firstSymbol = null;
|
||||||
|
Symbol lastSymbol = null;
|
||||||
|
long discoveredPltSpacing = Long.MAX_VALUE;
|
||||||
|
Map<Long, Integer> spacingCounts = new HashMap<>();
|
||||||
|
for (Symbol sym : elfLoadHelper.getProgram()
|
||||||
|
.getSymbolTable()
|
||||||
|
.getSymbolIterator(minSymbolSearchAddress, true)) {
|
||||||
|
if (sym.getSource() == SourceType.DEFAULT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Address addr = sym.getAddress();
|
||||||
|
if (addr.compareTo(maxSymbolSearchAddress) > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (firstSymbol == null) {
|
||||||
|
firstSymbol = sym;
|
||||||
|
}
|
||||||
|
if (pltSpacing == 0) {
|
||||||
|
// Collect spacing samples if PLT spacing is unknown
|
||||||
|
if (lastSymbol != null) {
|
||||||
|
long spacing = addr.subtract(lastSymbol.getAddress());
|
||||||
|
if (spacing > MAX_SUPPORTED_PLT_ENTRY_SIZE) {
|
||||||
|
lastSymbol = null; // reset on large symbol spacing
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int count =
|
||||||
|
spacingCounts.compute(spacing, (k, v) -> (v == null) ? 1 : v + 1);
|
||||||
|
discoveredPltSpacing = Math.min(discoveredPltSpacing, spacing);
|
||||||
|
if (count == PLT_SYMBOL_SAMPLE_COUNT_THRESHOLD) {
|
||||||
|
break; // stop on 10 occurances of the same spacing (rather arbitrary sample limit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastSymbol = sym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pltSpacing == 0) {
|
||||||
|
if (discoveredPltSpacing == Long.MAX_VALUE ||
|
||||||
|
spacingCounts.get(discoveredPltSpacing) == 1) { // NOTE: required number of symbol-spacing samples could be increased from 1
|
||||||
|
return; // PLT spacing not determined / too large or insufficient PLT symbols - skip PLT processing
|
||||||
|
}
|
||||||
|
pltSpacing = discoveredPltSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstSymbol != null) {
|
||||||
|
// use PLT symbol if found to identify start of first PLT entry
|
||||||
|
int firstSymbolEntryIndex = -1;
|
||||||
|
Address firstSymbolAddr = firstSymbol.getAddress();
|
||||||
|
int entryIndex = 0;
|
||||||
|
for (PltGotSymbol entrySymbol : pltGotSymbols) {
|
||||||
|
if (firstSymbolAddr
|
||||||
|
.equals(elfLoadHelper.getElfSymbolAddress(entrySymbol.elfSymbol))) {
|
||||||
|
firstSymbolEntryIndex = entryIndex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++entryIndex;
|
||||||
|
}
|
||||||
|
if (firstSymbolEntryIndex >= 0) {
|
||||||
|
firstPltEntryAddr = firstSymbolAddr;
|
||||||
|
if (firstSymbolEntryIndex > 0) {
|
||||||
|
firstPltEntryAddr =
|
||||||
|
firstPltEntryAddr.subtract(firstSymbolEntryIndex * pltSpacing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstPltEntryAddr == null) {
|
||||||
|
return; // failed to identify first PLT entry - skip PLT processing
|
||||||
|
}
|
||||||
|
|
||||||
|
Address pltEnd = firstPltEntryAddr.add(pltSpacing * (pltEntryCount - 1));
|
||||||
|
processLinkageTable("PLT", firstPltEntryAddr, pltEnd, monitor);
|
||||||
}
|
}
|
||||||
catch (NotFoundException e) {
|
catch (Exception e) {
|
||||||
throw new AssertException(e);
|
String msg = "Failed to process " + pltGotType + ": " + e.getMessage();
|
||||||
}
|
log(msg);
|
||||||
catch (AddressOutOfBoundsException e) {
|
Msg.error(this, msg, e);
|
||||||
log("Failed to process GOT: " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,20 +358,47 @@ public class ElfDefaultGotPltMarkup {
|
||||||
private void processGOT(Address gotStart, Address gotEnd, TaskMonitor monitor)
|
private void processGOT(Address gotStart, Address gotEnd, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
boolean imageBaseAlreadySet = elf.isPreLinked();
|
// Bail if GOT was previously marked-up or not within initialized memory
|
||||||
|
MemoryBlock block = memory.getBlock(gotStart);
|
||||||
|
if (block == null || !block.isInitialized()) {
|
||||||
|
return; // unsupported memory region - skip GOT processing
|
||||||
|
}
|
||||||
|
Data data = program.getListing().getDataAt(gotStart);
|
||||||
|
if (data == null || !Undefined.isUndefined(data.getDataType())) {
|
||||||
|
return; // evidence of prior markup - skip GOT processing
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Address newImageBase = null;
|
// Fixup first GOT entry which frequently refers to _DYNAMIC but generally lacks relocation (e.g. .got.plt)
|
||||||
while (gotStart.compareTo(gotEnd) <= 0) {
|
ElfDynamicTable dynamicTable = elf.getDynamicTable();
|
||||||
monitor.checkCanceled();
|
long imageBaseAdj = elfLoadHelper.getImageBaseWordAdjustmentOffset();
|
||||||
|
if (dynamicTable != null && imageBaseAdj != 0) {
|
||||||
|
long entry1Value = elfLoadHelper.getOriginalValue(gotStart, false);
|
||||||
|
if (entry1Value == dynamicTable.getAddressOffset()) {
|
||||||
|
// TODO: record artificial relative relocation for reversion/export concerns
|
||||||
|
entry1Value += imageBaseAdj; // adjust first entry value
|
||||||
|
if (elf.is64Bit()) {
|
||||||
|
memory.setLong(gotStart, entry1Value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memory.setInt(gotStart, (int) entry1Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Data data = createPointer(gotStart, true);
|
boolean imageBaseAlreadySet = elf.isPreLinked();
|
||||||
|
|
||||||
|
Address newImageBase = null;
|
||||||
|
Address nextGotAddr = gotStart;
|
||||||
|
while (nextGotAddr.compareTo(gotEnd) <= 0) {
|
||||||
|
|
||||||
|
data = createPointer(nextGotAddr, true);
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
gotStart = data.getMaxAddress().add(1);
|
nextGotAddr = data.getMaxAddress().add(1);
|
||||||
}
|
}
|
||||||
catch (AddressOutOfBoundsException e) {
|
catch (AddressOutOfBoundsException e) {
|
||||||
break; // no more room
|
break; // no more room
|
||||||
|
@ -208,20 +418,20 @@ public class ElfDefaultGotPltMarkup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (CodeUnitInsertionException e) {
|
catch (Exception e) {
|
||||||
log("Failed to process GOT: " + e.getMessage());
|
String msg = "Failed to process GOT at " + gotStart + ": " + e.getMessage();
|
||||||
}
|
log(msg);
|
||||||
catch (AddressOverflowException e) {
|
Msg.error(this, msg, e);
|
||||||
log("Failed to adjust image base: " + e.getMessage());
|
|
||||||
}
|
|
||||||
catch (LockException e) {
|
|
||||||
throw new AssertException(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processPLTSection(TaskMonitor monitor) throws CancelledException {
|
private void processPLTSection(TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
// TODO: Handle case where PLT is non-executable pointer table
|
// TODO: May want to consider using analysis to fully disassemble PLT, we only
|
||||||
|
// really need to migrate external symbols contained within the PLT
|
||||||
|
|
||||||
|
// FIXME: Code needs help ... bad assumption about PLT head size (e.g., 16)
|
||||||
|
int assumedPltHeadSize = 16;
|
||||||
|
|
||||||
if (elf.isRelocatable()) {
|
if (elf.isRelocatable()) {
|
||||||
return; //relocatable files do not have .PLT sections
|
return; //relocatable files do not have .PLT sections
|
||||||
|
@ -229,17 +439,15 @@ public class ElfDefaultGotPltMarkup {
|
||||||
|
|
||||||
MemoryBlock pltBlock = memory.getBlock(ElfSectionHeaderConstants.dot_plt);
|
MemoryBlock pltBlock = memory.getBlock(ElfSectionHeaderConstants.dot_plt);
|
||||||
// TODO: This is a band-aid since there are many PLT implementations and this assumes only one.
|
// TODO: This is a band-aid since there are many PLT implementations and this assumes only one.
|
||||||
if (pltBlock == null || !pltBlock.isExecute() ||
|
if (pltBlock == null || !pltBlock.isExecute() || pltBlock.getSize() <= assumedPltHeadSize) {
|
||||||
pltBlock.getSize() <= ElfConstants.PLT_ENTRY_SIZE) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int skipPointers = ElfConstants.PLT_ENTRY_SIZE;
|
int skipPointers = assumedPltHeadSize;
|
||||||
|
|
||||||
// ARM, AARCH64 and others may not store pointers at start of .plt
|
// ARM, AARCH64 and others may not store pointers at start of .plt
|
||||||
if (elf.e_machine() == ElfConstants.EM_ARM || elf.e_machine() == ElfConstants.EM_AARCH64) {
|
if (elf.e_machine() == ElfConstants.EM_ARM || elf.e_machine() == ElfConstants.EM_AARCH64) {
|
||||||
// TODO: Should be handled by extension
|
skipPointers = 0; // disassemble entire PLT
|
||||||
skipPointers = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process PLT section
|
// Process PLT section
|
||||||
|
@ -248,37 +456,6 @@ public class ElfDefaultGotPltMarkup {
|
||||||
processLinkageTable(ElfSectionHeaderConstants.dot_plt, minAddress, maxAddress, monitor);
|
processLinkageTable(ElfSectionHeaderConstants.dot_plt, minAddress, maxAddress, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processDynamicPLT(Address gotStart, Address gotEnd, TaskMonitor monitor)
|
|
||||||
throws CancelledException {
|
|
||||||
|
|
||||||
Address pltStart = null;
|
|
||||||
Address pltEnd = null;
|
|
||||||
|
|
||||||
for (Data gotPtr : listing.getDefinedData(new AddressSet(gotStart.next(), gotEnd), true)) {
|
|
||||||
monitor.checkCanceled();
|
|
||||||
if (!gotPtr.isPointer()) {
|
|
||||||
Msg.error(this, "ELF PLTGOT contains non-pointer");
|
|
||||||
return; // unexpected
|
|
||||||
}
|
|
||||||
Address ptr = (Address) gotPtr.getValue();
|
|
||||||
if (ptr.getOffset() == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
MemoryBlock block = memory.getBlock(ptr);
|
|
||||||
if (block == null || block.getName().equals(MemoryBlock.EXTERNAL_BLOCK_NAME)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (pltStart == null) {
|
|
||||||
pltStart = ptr;
|
|
||||||
}
|
|
||||||
pltEnd = ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pltStart != null) {
|
|
||||||
processLinkageTable("PLT", pltStart, pltEnd, monitor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform disassembly and markup of specified external linkage table which
|
* Perform disassembly and markup of specified external linkage table which
|
||||||
* consists of thunks to external functions. If symbols are defined within the
|
* consists of thunks to external functions. If symbols are defined within the
|
||||||
|
@ -292,16 +469,24 @@ public class ElfDefaultGotPltMarkup {
|
||||||
public void processLinkageTable(String pltName, Address minAddress, Address maxAddress,
|
public void processLinkageTable(String pltName, Address minAddress, Address maxAddress,
|
||||||
TaskMonitor monitor) throws CancelledException {
|
TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
// Disassemble section.
|
try {
|
||||||
// Disassembly is only done so we can see all instructions since many
|
// Disassemble section.
|
||||||
// of them are unreachable after applying relocations
|
// Disassembly is only done so we can see all instructions since many
|
||||||
disassemble(minAddress, maxAddress, program, monitor);
|
// of them are unreachable after applying relocations
|
||||||
|
disassemble(minAddress, maxAddress, program, monitor);
|
||||||
|
|
||||||
// Any symbols in the linkage section should be converted to External function thunks
|
// Any symbols in the linkage section should be converted to External function thunks
|
||||||
// This can be seen with ARM Android examples.
|
// This can be seen with ARM Android examples.
|
||||||
int count = convertSymbolsToExternalFunctions(minAddress, maxAddress);
|
int count = convertSymbolsToExternalFunctions(minAddress, maxAddress);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
log("Converted " + count + " " + pltName + " section symbols to external thunks");
|
log("Converted " + count + " " + pltName + " section symbols to external thunks");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
String msg =
|
||||||
|
"Failed to process " + pltName + " at " + minAddress + ": " + e.getMessage();
|
||||||
|
log(msg);
|
||||||
|
Msg.error(this, msg, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,15 +526,13 @@ public class ElfDefaultGotPltMarkup {
|
||||||
|
|
||||||
private void disassemble(Address start, Address end, Program prog, TaskMonitor monitor)
|
private void disassemble(Address start, Address end, Program prog, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
DisassemblerMessageListener dml = msg -> {
|
|
||||||
//don't care...
|
|
||||||
};
|
|
||||||
// TODO: Should we restrict disassembly or follows flows?
|
// TODO: Should we restrict disassembly or follows flows?
|
||||||
AddressSet set = new AddressSet(start, end);
|
AddressSet set = new AddressSet(start, end);
|
||||||
Disassembler disassembler = Disassembler.getDisassembler(prog, monitor, dml);
|
Disassembler disassembler = Disassembler.getDisassembler(prog, monitor, m -> {
|
||||||
|
/* silent */});
|
||||||
while (!set.isEmpty()) {
|
while (!set.isEmpty()) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
AddressSet disset = disassembler.disassemble(set.getMinAddress(), set, true);
|
AddressSet disset = disassembler.disassemble(set.getMinAddress(), null, true);
|
||||||
if (disset.isEmpty()) {
|
if (disset.isEmpty()) {
|
||||||
// Stop on first error but discard error bookmark since
|
// Stop on first error but discard error bookmark since
|
||||||
// some plt sections are partly empty and must rely
|
// some plt sections are partly empty and must rely
|
||||||
|
@ -444,6 +627,8 @@ public class ElfDefaultGotPltMarkup {
|
||||||
* then the base of the .so is most likely incorrect. Shift it!
|
* then the base of the .so is most likely incorrect. Shift it!
|
||||||
*/
|
*/
|
||||||
private Address UglyImageBaseCheck(Data data, Address imageBase) {
|
private Address UglyImageBaseCheck(Data data, Address imageBase) {
|
||||||
|
// TODO: Find sample - e.g., ARM .so - seems too late in import processing to change image base
|
||||||
|
// if any relocations have been applied.
|
||||||
if (elf.e_machine() != ElfConstants.EM_ARM) {
|
if (elf.e_machine() != ElfConstants.EM_ARM) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -530,6 +530,11 @@ public class ElfHeader implements StructConverter, Writeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
long relocTableOffset = relocTableLoadHeader.getOffset(relocTableAddr);
|
long relocTableOffset = relocTableLoadHeader.getOffset(relocTableAddr);
|
||||||
|
for (ElfRelocationTable relocTable : relocationTableList) {
|
||||||
|
if (relocTable.getFileOffset() == relocTableOffset) {
|
||||||
|
return; // skip reloc table previously parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
long tableEntrySize =
|
long tableEntrySize =
|
||||||
relocEntrySizeType != null ? dynamicTable.getDynamicValue(relocEntrySizeType) : -1;
|
relocEntrySizeType != null ? dynamicTable.getDynamicValue(relocEntrySizeType) : -1;
|
||||||
long tableSize = dynamicTable.getDynamicValue(relocTableSizeType);
|
long tableSize = dynamicTable.getDynamicValue(relocTableSizeType);
|
||||||
|
|
|
@ -21,6 +21,7 @@ import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressRange;
|
import ghidra.program.model.address.AddressRange;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.symbol.Namespace;
|
import ghidra.program.model.symbol.Namespace;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
@ -188,4 +189,18 @@ public interface ElfLoadHelper {
|
||||||
*/
|
*/
|
||||||
public AddressRange allocateLinkageBlock(int alignment, int size, String purpose);
|
public AddressRange allocateLinkageBlock(int alignment, int size, String purpose);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Get the original memory value at the specified address if a relocation was applied at the
|
||||||
|
* specified address (not containing). Current memory value will be returned if no relocation
|
||||||
|
* has been applied at specified address. The value size is either 8-bytes if {@link ElfHeader#is64Bit()},
|
||||||
|
* otherwise it will be 4-bytes. This is primarily intended to inspect original bytes within
|
||||||
|
* the GOT which may have had relocations applied to them.
|
||||||
|
* @param addr memory address
|
||||||
|
* @param signExtend if true sign-extend to long, else treat as unsigned
|
||||||
|
* @return original bytes value
|
||||||
|
* @throws MemoryAccessException if memory read fails
|
||||||
|
*/
|
||||||
|
public long getOriginalValue(Address addr, boolean signExtend)
|
||||||
|
throws MemoryAccessException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ package ghidra.app.util.bin.format.elf.relocation;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.elf.*;
|
import ghidra.app.util.bin.format.elf.*;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
@ -125,7 +127,7 @@ abstract public class ElfRelocationHandler implements ExtensionPoint {
|
||||||
public static void markAsUnhandled(Program program, Address relocationAddress, long type,
|
public static void markAsUnhandled(Program program, Address relocationAddress, long type,
|
||||||
long symbolIndex, String symbolName, MessageLog log) {
|
long symbolIndex, String symbolName, MessageLog log) {
|
||||||
|
|
||||||
symbolName = symbolName == null ? "<no name>" : symbolName;
|
symbolName = StringUtils.isEmpty(symbolName) ? "<no name>" : symbolName;
|
||||||
log.appendMsg("Unhandled Elf Relocation: Type = " + type + " (0x" + Long.toHexString(type) +
|
log.appendMsg("Unhandled Elf Relocation: Type = " + type + " (0x" + Long.toHexString(type) +
|
||||||
") at " + relocationAddress + " (Symbol = " + symbolName + ")");
|
") at " + relocationAddress + " (Symbol = " + symbolName + ")");
|
||||||
BookmarkManager bookmarkManager = program.getBookmarkManager();
|
BookmarkManager bookmarkManager = program.getBookmarkManager();
|
||||||
|
|
|
@ -43,6 +43,7 @@ import ghidra.program.model.data.DataUtilities.ClearDataMode;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
|
import ghidra.program.model.reloc.Relocation;
|
||||||
import ghidra.program.model.reloc.RelocationTable;
|
import ghidra.program.model.reloc.RelocationTable;
|
||||||
import ghidra.program.model.scalar.Scalar;
|
import ghidra.program.model.scalar.Scalar;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
|
@ -911,6 +912,23 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getOriginalValue(Address addr, boolean signExtend) throws MemoryAccessException {
|
||||||
|
byte[] bytes;
|
||||||
|
int len = elf.is64Bit() ? 8 : 4;
|
||||||
|
Relocation relocation = program.getRelocationTable().getRelocation(addr);
|
||||||
|
if (relocation == null) {
|
||||||
|
bytes = new byte[len];
|
||||||
|
memory.getBytes(addr, bytes);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bytes = relocation.getBytes();
|
||||||
|
}
|
||||||
|
DataConverter dataConverter = DataConverter.getInstance(elf.isBigEndian());
|
||||||
|
return signExtend ? dataConverter.getSignedValue(bytes, len)
|
||||||
|
: dataConverter.getValue(bytes, len);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add reference to previously applied header structure (assumes markupElfHeader previously called)
|
* Add reference to previously applied header structure (assumes markupElfHeader previously called)
|
||||||
* @param componentName
|
* @param componentName
|
||||||
|
|
|
@ -727,7 +727,8 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||||
stubsBlock.getEnd(), monitor);
|
stubsBlock.getEnd(), monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fixupGot(ElfLoadHelper elfLoadHelper, TaskMonitor monitor) {
|
private void fixupGot(ElfLoadHelper elfLoadHelper, TaskMonitor monitor)
|
||||||
|
throws CancelledException {
|
||||||
|
|
||||||
// see Wiki at https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT
|
// see Wiki at https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT
|
||||||
// see related doc at https://www.cr0.org/paper/mips.elf.external.resolution.txt
|
// see related doc at https://www.cr0.org/paper/mips.elf.external.resolution.txt
|
||||||
|
@ -764,6 +765,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
// process local symbol got entries
|
// process local symbol got entries
|
||||||
for (int i = 0; i < gotLocalEntryCount; i++) {
|
for (int i = 0; i < gotLocalEntryCount; i++) {
|
||||||
|
monitor.checkCanceled();
|
||||||
Address gotEntryAddr =
|
Address gotEntryAddr =
|
||||||
adjustTableEntryIfNonZero(gotBaseAddress, i, imageShift, elfLoadHelper);
|
adjustTableEntryIfNonZero(gotBaseAddress, i, imageShift, elfLoadHelper);
|
||||||
Data pointerData = elfLoadHelper.createData(gotEntryAddr, PointerDataType.dataType);
|
Data pointerData = elfLoadHelper.createData(gotEntryAddr, PointerDataType.dataType);
|
||||||
|
@ -775,6 +777,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||||
// process global/external symbol got entries
|
// process global/external symbol got entries
|
||||||
int gotIndex = gotLocalEntryCount;
|
int gotIndex = gotLocalEntryCount;
|
||||||
for (int i = gotSymbolIndex; i < elfSymbols.length; i++) {
|
for (int i = gotSymbolIndex; i < elfSymbols.length; i++) {
|
||||||
|
monitor.checkCanceled();
|
||||||
Address gotEntryAddr = adjustTableEntryIfNonZero(gotBaseAddress, gotIndex++,
|
Address gotEntryAddr = adjustTableEntryIfNonZero(gotBaseAddress, gotIndex++,
|
||||||
imageShift, elfLoadHelper);
|
imageShift, elfLoadHelper);
|
||||||
Data pointerData = elfLoadHelper.createData(gotEntryAddr, PointerDataType.dataType);
|
Data pointerData = elfLoadHelper.createData(gotEntryAddr, PointerDataType.dataType);
|
||||||
|
@ -795,7 +798,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fixupMipsGot(ElfLoadHelper elfLoadHelper, TaskMonitor monitor) {
|
private void fixupMipsGot(ElfLoadHelper elfLoadHelper, TaskMonitor monitor) throws CancelledException {
|
||||||
|
|
||||||
ElfHeader elfHeader = elfLoadHelper.getElfHeader();
|
ElfHeader elfHeader = elfLoadHelper.getElfHeader();
|
||||||
ElfDynamicTable dynamicTable = elfHeader.getDynamicTable();
|
ElfDynamicTable dynamicTable = elfHeader.getDynamicTable();
|
||||||
|
@ -830,6 +833,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||||
// process local symbol got entries
|
// process local symbol got entries
|
||||||
int gotEntryIndex = 1;
|
int gotEntryIndex = 1;
|
||||||
for (int i = 0; i < gotSymbolIndex; i++) {
|
for (int i = 0; i < gotSymbolIndex; i++) {
|
||||||
|
monitor.checkCanceled();
|
||||||
if (!elfSymbols[i].isFunction() || elfSymbols[i].getSectionHeaderIndex() != 0) {
|
if (!elfSymbols[i].isFunction() || elfSymbols[i].getSectionHeaderIndex() != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -849,6 +853,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
private Address adjustTableEntryIfNonZero(Address tableBaseAddr, int entryIndex,
|
private Address adjustTableEntryIfNonZero(Address tableBaseAddr, int entryIndex,
|
||||||
long adjustment, ElfLoadHelper elfLoadHelper) throws MemoryAccessException {
|
long adjustment, ElfLoadHelper elfLoadHelper) throws MemoryAccessException {
|
||||||
|
// TODO: record artificial relative relocation for reversion/export concerns
|
||||||
boolean is64Bit = elfLoadHelper.getElfHeader().is64Bit();
|
boolean is64Bit = elfLoadHelper.getElfHeader().is64Bit();
|
||||||
Memory memory = elfLoadHelper.getProgram().getMemory();
|
Memory memory = elfLoadHelper.getProgram().getMemory();
|
||||||
Address tableEntryAddr;
|
Address tableEntryAddr;
|
||||||
|
@ -871,6 +876,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
private Address setTableEntryIfZero(Address tableBaseAddr, int entryIndex, long value,
|
private Address setTableEntryIfZero(Address tableBaseAddr, int entryIndex, long value,
|
||||||
ElfLoadHelper elfLoadHelper) throws MemoryAccessException {
|
ElfLoadHelper elfLoadHelper) throws MemoryAccessException {
|
||||||
|
// TODO: record artificial relative relocation for reversion/export concerns
|
||||||
boolean is64Bit = elfLoadHelper.getElfHeader().is64Bit();
|
boolean is64Bit = elfLoadHelper.getElfHeader().is64Bit();
|
||||||
Memory memory = elfLoadHelper.getProgram().getMemory();
|
Memory memory = elfLoadHelper.getProgram().getMemory();
|
||||||
Address tableEntryAddr;
|
Address tableEntryAddr;
|
||||||
|
|
|
@ -35,6 +35,9 @@ import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class PowerPC64_ElfExtension extends ElfExtension {
|
public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
|
private static final int PLT_ENTRY_SIZE = 8; // could be 16(local) or 24 w/ opd_api, 32 for VxWorks
|
||||||
|
private static final int PLT_HEAD_SIZE = 16; // could be 24 w/ obd_api, 32 for VxWorks
|
||||||
|
|
||||||
// Elf Dynamic Type Extensions
|
// Elf Dynamic Type Extensions
|
||||||
public static final ElfDynamicType DT_PPC64_GLINK = new ElfDynamicType(0x70000000,
|
public static final ElfDynamicType DT_PPC64_GLINK = new ElfDynamicType(0x70000000,
|
||||||
"DT_PPC64_GLINK", "Specify the start of the .glink section", ElfDynamicValueType.ADDRESS);
|
"DT_PPC64_GLINK", "Specify the start of the .glink section", ElfDynamicValueType.ADDRESS);
|
||||||
|
@ -225,8 +228,7 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
}
|
}
|
||||||
Program program = elfLoadHelper.getProgram();
|
Program program = elfLoadHelper.getProgram();
|
||||||
MemoryBlock pltBlock = program.getMemory().getBlock(pltSection.getNameAsString());
|
MemoryBlock pltBlock = program.getMemory().getBlock(pltSection.getNameAsString());
|
||||||
// TODO: This is a band-aid since there are many PLT implementations and this assumes only one.
|
if (pltBlock == null) {
|
||||||
if (pltBlock == null || pltBlock.getSize() <= ElfConstants.PLT_ENTRY_SIZE) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (pltSection.isExecutable()) {
|
if (pltSection.isExecutable()) {
|
||||||
|
@ -243,14 +245,14 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
// TODO: Uncertain
|
// TODO: Uncertain
|
||||||
|
|
||||||
Address addr = pltBlock.getStart().add(ElfConstants.PLT_ENTRY_SIZE);
|
Address addr = pltBlock.getStart().add(PLT_HEAD_SIZE);
|
||||||
try {
|
try {
|
||||||
while (addr.compareTo(pltBlock.getEnd()) < 0) {
|
while (addr.compareTo(pltBlock.getEnd()) < 0) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
if (elfLoadHelper.createData(addr, PointerDataType.dataType) == null) {
|
if (elfLoadHelper.createData(addr, PointerDataType.dataType) == null) {
|
||||||
break; // stop early if failed to create a pointer
|
break; // stop early if failed to create a pointer
|
||||||
}
|
}
|
||||||
addr = addr.addNoWrap(8);
|
addr = addr.addNoWrap(PLT_ENTRY_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (AddressOverflowException e) {
|
catch (AddressOverflowException e) {
|
||||||
|
|
|
@ -28,8 +28,6 @@ import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class X86_32_ElfExtension extends ElfExtension {
|
public class X86_32_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
// TODO: Add extension types
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canHandle(ElfHeader elf) {
|
public boolean canHandle(ElfHeader elf) {
|
||||||
return elf.e_machine() == ElfConstants.EM_386 && elf.is32Bit();
|
return elf.e_machine() == ElfConstants.EM_386 && elf.is32Bit();
|
||||||
|
@ -90,8 +88,7 @@ public class X86_32_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
// MemoryBlock pltBlock = getBlockPLT(pltSection);
|
// MemoryBlock pltBlock = getBlockPLT(pltSection);
|
||||||
MemoryBlock pltBlock = memory.getBlock(pltSection.getNameAsString());
|
MemoryBlock pltBlock = memory.getBlock(pltSection.getNameAsString());
|
||||||
// TODO: This is a band-aid since there are many PLT implementations and this assumes only one.
|
if (pltBlock == null) {
|
||||||
if (pltBlock == null || pltBlock.getSize() <= ElfConstants.PLT_ENTRY_SIZE) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue