From 6107f29a95e9652df8c6ab843b3d0e78f1be60bc Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Fri, 23 Oct 2020 18:57:11 -0400 Subject: [PATCH] GP-302 corrected issue affected ELF PLTGOT bounds determination. Corrected various pointer and data related issues --- .../core/disassembler/AddressTable.java | 12 ++- .../format/elf/ElfDefaultGotPltMarkup.java | 91 ++++++++++++++----- .../program/model/data/DataUtilities.java | 27 ++++-- .../program/model/data/PointerDataType.java | 6 +- .../format/elf/extend/MIPS_ElfExtension.java | 19 +--- .../elf/extend/PowerPC64_ElfExtension.java | 3 + 6 files changed, 105 insertions(+), 53 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTable.java index 606ce532e3..79202a7e6e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/AddressTable.java @@ -217,7 +217,7 @@ public class AddressTable { * @param end end index (inclusive) * @param createIndex don't create index if false * @param autoLabel true if labels should be created on the table - * @return + * @return true if tablecreated else false */ public boolean makeTable(Program program, int start, int end, boolean createIndex, boolean autoLabel) { @@ -236,13 +236,17 @@ public class AddressTable { //TODO: Do I need to do something special for the 3 byte pointers or will it know // how to make it automatically? + DataTypeManager dtm = program.getDataTypeManager(); if (shiftedAddr) { adt = ShiftedAddressDataType.dataType; } - else { - adt = new PointerDataType(DataType.DEFAULT, addrSize); + else if (addrSize == program.getDefaultPointerSize()) { + adt = new PointerDataType(DataType.DEFAULT, dtm); } - adt = program.getDataTypeManager().resolve(adt, null); + else { + adt = new PointerDataType(DataType.DEFAULT, addrSize, dtm); + } + adt = dtm.resolve(adt, null); Address newAddress = currentAddress; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java index 9ad6a24656..8b185e485d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfDefaultGotPltMarkup.java @@ -122,20 +122,37 @@ public class ElfDefaultGotPltMarkup { if (relocationTable == null) { return; } - ElfRelocation[] relocations = relocationTable.getRelocations(); - int count = relocations.length; - // First few entries of GOT do not correspond to dynamic symbols. - // First relocation address must be used to calculate GOT end address - // based upon the total number of relocation entries. - long firstGotEntryOffset = relocations[0].getOffset() + imageBaseAdj; + // External dynamic symbol entries in the PLTGOT, if any, will be placed + // after any local symbol entries. + + // While DT_PLTGOT identifies the start of the PLTGOT it does not + // specify its length. If there are dynamic non-local entries in the + // PLTGOT they should have relocation entries in the table identified + // by DT_JMPREL. It is important to note that this relocation table + // can include entries which affect other processor-specific PLTGOT + // tables (e.g., MIPS_PLTGOT) so we must attempt to isolate the + // entries which correspond to DT_PLTGOT. + + // 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( - dynamicTable.getDynamicValue(ElfDynamicType.DT_PLTGOT)) + imageBaseAdj; + dynamicTable.getDynamicValue(ElfDynamicType.DT_PLTGOT)); + + ElfRelocation[] relocations = relocationTable.getRelocations(); + + long lastGotOffset = relocations[relocations.length - 1].getOffset(); + if (lastGotOffset < pltgot) { + return; + } + + Address gotStart = defaultSpace.getAddress(pltgot + imageBaseAdj); + Address gotEnd = defaultSpace.getAddress(lastGotOffset + imageBaseAdj); - Address gotStart = defaultSpace.getAddress(pltgot); - Address gotEnd = defaultSpace.getAddress( - firstGotEntryOffset + (count * defaultSpace.getPointerSize()) - 1); processGOT(gotStart, gotEnd, monitor); processDynamicPLT(gotStart, gotEnd, monitor); } @@ -162,7 +179,7 @@ public class ElfDefaultGotPltMarkup { try { Address newImageBase = null; - while (gotStart.compareTo(gotEnd) < 0) { + while (gotStart.compareTo(gotEnd) <= 0) { monitor.checkCanceled(); Data data = createPointer(gotStart, true); @@ -350,7 +367,7 @@ public class ElfDefaultGotPltMarkup { return null; } int pointerSize = program.getDataTypeManager().getDataOrganization().getPointerSize(); - Pointer pointer = PointerDataType.dataType; + Pointer pointer = PointerDataType.dataType.clone(program.getDataTypeManager()); if (elf.is32Bit() && pointerSize != 4) { pointer = Pointer32DataType.dataType; } @@ -364,20 +381,50 @@ public class ElfDefaultGotPltMarkup { } data = listing.createData(addr, pointer); } - Address refAddr = (Address) data.getValue(); - if (keepRefWhenValid) { - if (memory.contains(refAddr)) { - return data; - } - Symbol syms[] = program.getSymbolTable().getSymbols(refAddr); - if (syms != null && syms.length > 0 && syms[0].getSource() != SourceType.DEFAULT) { - return data; - } + if (keepRefWhenValid && isValidPointer(data)) { + setConstant(data); + } + else { + removeMemRefs(data); } - removeMemRefs(data); return data; } + /** + * Set specified data as constant if contained within a writable block. It can be helpful + * to the decompiler results if constant pointers are marked as such (e.g., GOT entries) + * @param data program data + */ + public static void setConstant(Data data) { + Memory memory = data.getProgram().getMemory(); + MemoryBlock block = memory.getBlock(data.getAddress()); + if (!block.isWrite() || block.getName().startsWith(ElfSectionHeaderConstants.dot_got)) { + // .got blocks will be force to read-only by ElfDefaultGotPltMarkup + return; + } + data.setLong(MutabilitySettingsDefinition.MUTABILITY, + MutabilitySettingsDefinition.CONSTANT); + } + + /** + * Determine if pointerData refers to a valid memory address or symbol + * @param pointerData pointer data + * @return true if pointer data refers to valid memory address or symbol + */ + public static boolean isValidPointer(Data pointerData) { + Program program = pointerData.getProgram(); + Memory memory = program.getMemory(); + Address refAddr = (Address) pointerData.getValue(); + if (memory.contains(refAddr)) { + return true; + } + Symbol syms[] = program.getSymbolTable().getSymbols(refAddr); + if (syms != null && syms.length > 0 && syms[0].getSource() != SourceType.DEFAULT) { + return true; + } + return false; + } + private void removeMemRefs(Data data) { if (data != null) { Reference[] refs = data.getValueReferences(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataUtilities.java index 7d97369f6b..b4716f70dc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataUtilities.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataUtilities.java @@ -125,12 +125,19 @@ public final class DataUtilities { existingDataLen = data.getLength(); existingDT = data.getDataType(); + if (data.isDefined() && newDataType.isEquivalent(existingDT)) { + return data; + } + // Check for external reference on pointer - Reference[] refs = refMgr.getReferencesFrom(addr); - for (Reference ref : refs) { - if (ref.getOperandIndex() == 0 && ref.isExternalReference()) { - extRef = ref; - break; + if (existingDT instanceof Pointer) { + // TODO: This can probably be eliminated + Reference[] refs = refMgr.getReferencesFrom(addr); + for (Reference ref : refs) { + if (ref.getOperandIndex() == 0 && ref.isExternalReference()) { + extRef = ref; + break; + } } } } @@ -192,11 +199,11 @@ public final class DataUtilities { private static void checkEnoughSpace(Program program, Address addr, int existingDataLen, DataTypeInstance dti, ClearDataMode mode) throws CodeUnitInsertionException { Listing listing = program.getListing(); - int newSize = dti.getLength(); - if (newSize <= existingDataLen) { - listing.clearCodeUnits(addr, addr, false); - return; - } +// int newSize = dti.getLength(); +// if (newSize <= existingDataLen) { +// listing.clearCodeUnits(addr, addr, false); +// return; +// } try { Address end = addr.addNoWrap(existingDataLen - 1); Address newEnd = addr.addNoWrap(dti.getLength() - 1); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java index 3f15f23a68..75c30d8967 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java @@ -60,7 +60,7 @@ public class PointerDataType extends BuiltIn implements Pointer { * organization when resolved. */ public PointerDataType() { - this(null, -1, null); + this(DataType.DEFAULT, -1, null); } /** @@ -72,7 +72,7 @@ public class PointerDataType extends BuiltIn implements Pointer { * @param dtm data-type manager whose data organization should be used */ public PointerDataType(DataTypeManager dtm) { - this(null, -1, dtm); + this(DataType.DEFAULT, -1, dtm); } /** @@ -142,7 +142,7 @@ public class PointerDataType extends BuiltIn implements Pointer { } @Override - public final DataType clone(DataTypeManager dtm) { + public final Pointer clone(DataTypeManager dtm) { if (dtm == getDataTypeManager()) { return this; } diff --git a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/extend/MIPS_ElfExtension.java b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/extend/MIPS_ElfExtension.java index 99905b2361..99c1a8c366 100644 --- a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/extend/MIPS_ElfExtension.java +++ b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/extend/MIPS_ElfExtension.java @@ -744,7 +744,9 @@ public class MIPS_ElfExtension extends ElfExtension { Address gotEntryAddr = adjustTableEntryIfNonZero(gotBaseAddress, i, imageShift, elfLoadHelper); Data pointerData = elfLoadHelper.createData(gotEntryAddr, PointerDataType.dataType); - setConstant(pointerData); + if (ElfDefaultGotPltMarkup.isValidPointer(pointerData)) { + ElfDefaultGotPltMarkup.setConstant(pointerData); + } } // process global/external symbol got entries @@ -753,7 +755,7 @@ public class MIPS_ElfExtension extends ElfExtension { Address gotEntryAddr = adjustTableEntryIfNonZero(gotBaseAddress, gotIndex++, imageShift, elfLoadHelper); Data pointerData = elfLoadHelper.createData(gotEntryAddr, PointerDataType.dataType); - setConstant(pointerData); + ElfDefaultGotPltMarkup.setConstant(pointerData); if (elfSymbols[i].isFunction() && elfSymbols[i].getSectionHeaderIndex() == 0) { // ensure that external function/thunk are created in absence of sections Address refAddr = (Address) pointerData.getValue(); @@ -811,7 +813,7 @@ public class MIPS_ElfExtension extends ElfExtension { Address gotEntryAddr = adjustTableEntryIfNonZero(mipsPltgotBase, ++gotEntryIndex, imageShift, elfLoadHelper); Data pointerData = elfLoadHelper.createData(gotEntryAddr, PointerDataType.dataType); - setConstant(pointerData); + ElfDefaultGotPltMarkup.setConstant(pointerData); } } catch (NotFoundException e) { @@ -822,17 +824,6 @@ public class MIPS_ElfExtension extends ElfExtension { } } - private void setConstant(Data pointerData) { - Memory memory = pointerData.getProgram().getMemory(); - MemoryBlock block = memory.getBlock(pointerData.getAddress()); - if (!block.isWrite() || block.getName().startsWith(ElfSectionHeaderConstants.dot_got)) { - // .got blocks will be force to read-only by ElfDefaultGotPltMarkup - return; - } - pointerData.setLong(MutabilitySettingsDefinition.MUTABILITY, - MutabilitySettingsDefinition.CONSTANT); - } - private Address adjustTableEntryIfNonZero(Address tableBaseAddr, int entryIndex, long adjustment, ElfLoadHelper elfLoadHelper) throws MemoryAccessException { boolean is64Bit = elfLoadHelper.getElfHeader().is64Bit(); diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java index 591262ef7b..8c0e6cab82 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java @@ -368,6 +368,9 @@ public class PowerPC64_ElfExtension extends ElfExtension { return null; } + ElfDefaultGotPltMarkup.setConstant(refPtr); + ElfDefaultGotPltMarkup.setConstant(tocPtr); + Function function = program.getListing().getFunctionAt(refAddr); if (function == null) { // Check for potential pointer table (unsure a non-function would be referenced by OPD section)