diff --git a/src/main/java/adubbz/nx/common/ElfCompatibilityProvider.java b/src/main/java/adubbz/nx/common/ElfCompatibilityProvider.java index e40bc0a..72db352 100644 --- a/src/main/java/adubbz/nx/common/ElfCompatibilityProvider.java +++ b/src/main/java/adubbz/nx/common/ElfCompatibilityProvider.java @@ -6,14 +6,6 @@ */ package adubbz.nx.common; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import adubbz.nx.util.FullMemoryByteProvider; import adubbz.nx.util.LegacyBinaryReader; import ghidra.app.util.bin.BinaryReader; @@ -28,8 +20,13 @@ import ghidra.util.Msg; import ghidra.util.exception.NotFoundException; +import java.io.IOException; +import java.util.*; + public class ElfCompatibilityProvider { + public static final int R_FAKE_RELR = -1; + private Program program; private ByteProvider provider; private BinaryReader binaryReader; @@ -221,7 +218,7 @@ public List getRelocations() try { - if (dynamicTable.containsDynamicValue(ElfDynamicType.DT_REL.value)) + if (dynamicTable.containsDynamicValue(ElfDynamicType.DT_REL)) { Msg.info(this, "Processing DT_REL relocations..."); processRelocations(this.relocs, this.symbolTable, @@ -236,6 +233,13 @@ public List getRelocations() this.dynamicTable.getDynamicValue(ElfDynamicType.DT_RELA), this.dynamicTable.getDynamicValue(ElfDynamicType.DT_RELASZ)); } + + if (dynamicTable.containsDynamicValue(ElfDynamicType.DT_RELR)) { + Msg.info(this, "Processing DT_RELR relocations..."); + processReadOnlyRelocations(this.relocs, + this.dynamicTable.getDynamicValue(ElfDynamicType.DT_RELR), + this.dynamicTable.getDynamicValue(ElfDynamicType.DT_RELRSZ)); + } } catch (NotFoundException | IOException e) { @@ -297,6 +301,39 @@ private Set processRelocations(List relocs, ElfSymbolTable s } return locations; } + + private Set processReadOnlyRelocations(List relocs, long relr, long relrsz) throws IOException + { + Set locations = new HashSet<>(); + int relocSize = 0x8; + + long where = 0; + for (long i = 0; i < relrsz / relocSize; i++) + { + long base = this.program.getImageBase().getOffset(); + long entry = this.binaryReader.readLong(base + relr + i * relocSize); + + if ((entry & 1) != 0) { + entry >>= 1; + i = 0; + while (i < (relocSize * 8) - 1) { + if ((entry & (1L << i)) != 0) { + locations.add(where + i * relocSize); + relocs.add(new NXRelocation(where + i * relocSize, 0, R_FAKE_RELR, null, 0)); + } + i++; + } + where += relocSize * ((relocSize * 8) - 1); + } + else { + where = entry; + locations.add(where); + relocs.add(new NXRelocation(where, 0, R_FAKE_RELR, null, 0)); + where += 1; + } + } + return locations; + } protected MemoryBlock getDynamicBlock() { diff --git a/src/main/java/adubbz/nx/loader/common/NXProgramBuilder.java b/src/main/java/adubbz/nx/loader/common/NXProgramBuilder.java index 86c880c..4b3451e 100644 --- a/src/main/java/adubbz/nx/loader/common/NXProgramBuilder.java +++ b/src/main/java/adubbz/nx/loader/common/NXProgramBuilder.java @@ -47,6 +47,8 @@ import java.util.List; import java.util.Map; +import static adubbz.nx.common.ElfCompatibilityProvider.R_FAKE_RELR; + public class NXProgramBuilder { protected ByteProvider fileByteProvider; @@ -95,6 +97,7 @@ public void load(TaskMonitor monitor) this.tryCreateDynBlock(".fini_array", ElfDynamicType.DT_FINI_ARRAY, ElfDynamicType.DT_FINI_ARRAYSZ); this.tryCreateDynBlock(".rela.dyn", ElfDynamicType.DT_RELA, ElfDynamicType.DT_RELASZ); this.tryCreateDynBlock(".rel.dyn", ElfDynamicType.DT_REL, ElfDynamicType.DT_RELSZ); + this.tryCreateDynBlock(".relr.dyn", ElfDynamicType.DT_RELR, ElfDynamicType.DT_RELRSZ); if (adapter.isAarch32()) { @@ -266,10 +269,16 @@ protected void setupRelocations() throws AddressOutOfBoundsException, NotFoundEx this.pltEntries.add(new PltEntry(off, target)); } } - - long pltStart = this.pltEntries.get(0).off; - long pltEnd = this.pltEntries.get(this.pltEntries.size() - 1).off + 0x10; - this.memBlockHelper.addSection(".plt", pltStart, pltStart, pltEnd - pltStart, true, false, false); + + if (!this.pltEntries.isEmpty()) { + long pltStart = this.pltEntries.get(0).off; + long pltEnd = this.pltEntries.get(this.pltEntries.size() - 1).off + 0x10; + this.memBlockHelper.addSection(".plt", pltStart, pltStart, pltEnd - pltStart, true, false, false); + } + else { + // TODO: Find a way to locate the plt in CFI-enabled binaries. + Msg.error(this, "No PLT entries found, does this binary have CFI enabled? This loader currently can't locate the plt in them."); + } } protected void createGlobalOffsetTable() throws AddressOutOfBoundsException @@ -337,7 +346,16 @@ else if (reloc.r_type == AARCH64_ElfRelocationConstants.R_AARCH64_GLOB_DAT || else if (reloc.r_type == AARCH64_ElfRelocationConstants.R_AARCH64_RELATIVE) { program.getMemory().setLong(target, this.nxo.getBaseAddress() + reloc.addend); - } + } + else if (reloc.r_type == R_FAKE_RELR) { + if (this.nxo.getAdapter().isAarch32()) { + // TODO: Add RELRO support for 32-bit + Msg.error(this, "TODO: RELRO support for 32-bit"); + continue; + } + + program.getMemory().setLong(target, this.nxo.getBaseAddress() + originalValue); + } else { Msg.info(this, String.format("TODO: r_type 0x%x", reloc.r_type));