diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/chained/DyldChainedFixups.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/chained/DyldChainedFixups.java index b43ec8a59f..7a4c7cfecc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/chained/DyldChainedFixups.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/chained/DyldChainedFixups.java @@ -25,8 +25,9 @@ import ghidra.app.util.bin.format.macho.dyld.DyldChainedPtr.DyldChainType; import ghidra.app.util.bin.format.macho.dyld.DyldFixup; import ghidra.app.util.importer.MessageLog; import ghidra.app.util.opinion.MachoProgramBuilder; +import ghidra.app.util.opinion.MachoProgramUtils; import ghidra.program.model.address.Address; -import ghidra.program.model.listing.Program; +import ghidra.program.model.listing.*; import ghidra.program.model.mem.Memory; import ghidra.program.model.reloc.Relocation.Status; import ghidra.program.model.symbol.*; @@ -136,41 +137,79 @@ public class DyldChainedFixups { public static List
fixupChainedPointers(List fixups, Program program, Address imagebase, List libraryPaths, MessageLog log, TaskMonitor monitor) throws CancelledException { - List
fixedAddrs = new ArrayList<>(); if (fixups.isEmpty()) { - return fixedAddrs; + return List.of(); } + Memory memory = program.getMemory(); + SymbolTable symbolTable = program.getSymbolTable(); + ExternalManager extMgr = program.getExternalManager(); + + // Figure out how much space in the EXTERNAL block we need, and make it + Address extAddr = null; + try { + long externalSize = fixups.stream() + .filter(e -> e.value() == null && e.symbol() != null && e.libOrdinal() != null) + .mapToLong(DyldFixup::size) + .sum(); + if (externalSize > 0) { + extAddr = MachoProgramUtils.addExternalBlock(program, externalSize, log); + } + } + catch (Exception e) { + log.appendMsg( + "Failed to create space in EXTERNAL block for chained fixups: " + e.getMessage()); + } + + List
fixedAddrs = new ArrayList<>(); monitor.initialize(fixups.size(), "Fixing up chained pointers..."); for (DyldFixup fixup : fixups) { monitor.increment(); Status status = Status.UNSUPPORTED; - Address addr = imagebase.add(fixup.offset()); - String symbol = fixup.symbol(); + Address fixupAddr = imagebase.add(fixup.offset()); + Long fixupValue = fixup.value(); + String fixupSymbol = fixup.symbol(); long[] value = new long[] {}; try { - if (fixup.value() != null) { + if (fixupValue == null && fixupSymbol != null && fixup.libOrdinal() != null && + extAddr != null) { + try { + symbolTable.createLabel(extAddr, fixupSymbol, SourceType.IMPORTED); + fixupValue = extAddr.getOffset(); + Function stubFunc = MachoProgramBuilder.createOneByteFunction(program, + fixupSymbol, extAddr); + if (stubFunc != null) { + ExternalLocation loc = extMgr.addExtLocation(Library.UNKNOWN, + fixupSymbol, null, SourceType.IMPORTED); + stubFunc.setThunkedFunction(loc.createFunction()); + } + } + finally { + extAddr = extAddr.add(fixup.size()); + } + } + if (fixupValue != null) { if (fixup.size() == 8 || fixup.size() == 4) { if (fixup.size() == 8) { - memory.setLong(addr, fixup.value()); + memory.setLong(fixupAddr, fixupValue); } else { - memory.setInt(addr, fixup.value().intValue()); + memory.setInt(fixupAddr, fixupValue.intValue()); } - fixedAddrs.add(addr); - status = Status.APPLIED_OTHER; + fixedAddrs.add(fixupAddr); + status = Status.APPLIED; } - value = new long[] { fixup.value() }; + value = new long[] { fixupValue }; } - if (symbol != null && fixup.libOrdinal() != null) { + if (fixupSymbol != null && fixup.libOrdinal() != null) { value = new long[] { fixup.libOrdinal() }; try { MachoProgramBuilder.fixupExternalLibrary(program, libraryPaths, - fixup.libOrdinal(), symbol); + fixup.libOrdinal(), fixupSymbol); } catch (Exception e) { log.appendMsg("WARNING: Problem fixing up symbol '%s' - %s" - .formatted(symbol, e.getMessage())); + .formatted(fixupSymbol, e.getMessage())); } } } @@ -179,7 +218,7 @@ public class DyldChainedFixups { } finally { program.getRelocationTable() - .add(addr, status, RELOCATION_TYPE, value, fixup.size(), symbol); + .add(fixupAddr, status, RELOCATION_TYPE, value, fixup.size(), fixupSymbol); } } log.appendMsg("Fixed up " + fixedAddrs.size() + " chained pointers."); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java index 4f80607718..c63e36072e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java @@ -146,7 +146,7 @@ public abstract class AbstractClassicProcessor { status = Status.UNSUPPORTED; } else { - status = Status.APPLIED_OTHER; + status = Status.APPLIED; } // put an entry in the relocation table, handled or not diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/DyldCacheProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/DyldCacheProgramBuilder.java index 784c560e7b..bcb6e6cd03 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/DyldCacheProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/DyldCacheProgramBuilder.java @@ -150,7 +150,7 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder { if (entryPoint != null) { Address entryPointAddr = space.getAddress(entryPoint); program.getSymbolTable().addExternalEntryPoint(entryPointAddr); - createOneByteFunction("entry", entryPointAddr); + createOneByteFunction(program, "entry", entryPointAddr); } else { log.appendMsg("Unable to determine entry point."); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java index 509aa8cf91..368ad63abf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java @@ -514,7 +514,7 @@ public class MachoProgramBuilder { if (!realEntryFound) { program.getSymbolTable().createLabel(addr, "entry", SourceType.IMPORTED); program.getSymbolTable().addExternalEntryPoint(addr); - createOneByteFunction("entry", addr); + createOneByteFunction(program, "entry", addr); realEntryFound = true; } else { @@ -684,10 +684,11 @@ public class MachoProgramBuilder { monitor.increment(); int symbolIndex = indirectSymbols.get(i); NList symbol = symbolTableCommand.getSymbolAt(symbolIndex); - String name = - symbol != null ? SymbolUtilities.replaceInvalidChars(symbol.getString(), true) - : "STUB_" + startAddr; - Function stubFunc = createOneByteFunction(name, startAddr); + String name = null; + if (symbol != null) { + name = SymbolUtilities.replaceInvalidChars(symbol.getString(), true); + } + Function stubFunc = createOneByteFunction(program, name, startAddr); if (stubFunc != null && symbol != null) { ExternalLocation loc = program.getExternalManager() .addExtLocation(Library.UNKNOWN, name, null, SourceType.IMPORTED); @@ -965,8 +966,8 @@ public class MachoProgramBuilder { } finally { program.getRelocationTable() - .add(addr, success ? Status.APPLIED_OTHER : Status.FAILURE, - binding.getType(), null, bytes.length, binding.getSymbolName()); + .add(addr, success ? Status.APPLIED : Status.FAILURE, binding.getType(), + null, bytes.length, binding.getSymbolName()); } } } @@ -1584,7 +1585,7 @@ public class MachoProgramBuilder { } Register tModeRegister = program.getLanguage().getRegister("TMode"); program.getProgramContext().setValue(tModeRegister, address, address, BigInteger.ONE); - createOneByteFunction(null, address); + createOneByteFunction(program, null, address); } private void processLazyPointerSection(AddressSetView set) { @@ -1638,13 +1639,14 @@ public class MachoProgramBuilder { * create a one-byte function, so that when the code is analyzed, * it will be disassembled, and the function created with the correct body. * + * @param program The {@link Program} * @param name the name of the function * @param address location to create the function * @return If a function already existed at the given address, that function will be returned. * Otherwise, the newly created function will be returned. If there was a problem creating * the function, null will be returned. */ - Function createOneByteFunction(String name, Address address) { + public static Function createOneByteFunction(Program program, String name, Address address) { FunctionManager functionMgr = program.getFunctionManager(); Function function = functionMgr.getFunctionAt(address); if (function != null) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramUtils.java index 1a918f9e7a..51c26309c5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramUtils.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramUtils.java @@ -64,9 +64,9 @@ public class MachoProgramUtils { Address ret; if (externalBlock != null) { ret = externalBlock.getEnd().add(1); - MemoryBlock newBlock = mem.createBlock(externalBlock, "REEXPORTS", ret, size); + MemoryBlock newBlock = + mem.createBlock(externalBlock, MemoryBlock.EXTERNAL_BLOCK_NAME, ret, size); mem.join(externalBlock, newBlock); - //joinedBlock.setName(MemoryBlock.EXTERNAL_BLOCK_NAME); } else { ret = MachoProgramUtils.getNextAvailableAddress(program); diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/MachoExtractProgramBuilder.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/MachoExtractProgramBuilder.java index 84b3a25769..5cf3aa02c5 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/MachoExtractProgramBuilder.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/app/util/opinion/MachoExtractProgramBuilder.java @@ -113,7 +113,7 @@ public class MachoExtractProgramBuilder extends MachoProgramBuilder { // location to the newly exported function Function func = funcManager.getFunctionAt(sym.getAddress()); if (func != null && func.getThunkedFunction(false) != null) { - func.setThunkedFunction(createOneByteFunction(name, exportAddr)); + func.setThunkedFunction(createOneByteFunction(program, name, exportAddr)); // Remove the external location associated with the thunk function. // After the first delete, the external location becomes an external label, which