Merge remote-tracking branch 'origin/GP-5681_ryanmkurtz_macho' into

Ghidra_11.4 (Closes #8124)
This commit is contained in:
Ryan Kurtz 2025-05-20 17:19:49 -04:00
commit c594e41f60
6 changed files with 70 additions and 29 deletions

View file

@ -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.bin.format.macho.dyld.DyldFixup;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.MachoProgramBuilder; import ghidra.app.util.opinion.MachoProgramBuilder;
import ghidra.app.util.opinion.MachoProgramUtils;
import ghidra.program.model.address.Address; 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.mem.Memory;
import ghidra.program.model.reloc.Relocation.Status; import ghidra.program.model.reloc.Relocation.Status;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
@ -136,41 +137,79 @@ public class DyldChainedFixups {
public static List<Address> fixupChainedPointers(List<DyldFixup> fixups, Program program, public static List<Address> fixupChainedPointers(List<DyldFixup> fixups, Program program,
Address imagebase, List<String> libraryPaths, MessageLog log, TaskMonitor monitor) Address imagebase, List<String> libraryPaths, MessageLog log, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
List<Address> fixedAddrs = new ArrayList<>();
if (fixups.isEmpty()) { if (fixups.isEmpty()) {
return fixedAddrs; return List.of();
} }
Memory memory = program.getMemory(); 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<Address> fixedAddrs = new ArrayList<>();
monitor.initialize(fixups.size(), "Fixing up chained pointers..."); monitor.initialize(fixups.size(), "Fixing up chained pointers...");
for (DyldFixup fixup : fixups) { for (DyldFixup fixup : fixups) {
monitor.increment(); monitor.increment();
Status status = Status.UNSUPPORTED; Status status = Status.UNSUPPORTED;
Address addr = imagebase.add(fixup.offset()); Address fixupAddr = imagebase.add(fixup.offset());
String symbol = fixup.symbol(); Long fixupValue = fixup.value();
String fixupSymbol = fixup.symbol();
long[] value = new long[] {}; long[] value = new long[] {};
try { 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 || fixup.size() == 4) {
if (fixup.size() == 8) { if (fixup.size() == 8) {
memory.setLong(addr, fixup.value()); memory.setLong(fixupAddr, fixupValue);
} }
else { else {
memory.setInt(addr, fixup.value().intValue()); memory.setInt(fixupAddr, fixupValue.intValue());
} }
fixedAddrs.add(addr); fixedAddrs.add(fixupAddr);
status = Status.APPLIED_OTHER; 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() }; value = new long[] { fixup.libOrdinal() };
try { try {
MachoProgramBuilder.fixupExternalLibrary(program, libraryPaths, MachoProgramBuilder.fixupExternalLibrary(program, libraryPaths,
fixup.libOrdinal(), symbol); fixup.libOrdinal(), fixupSymbol);
} }
catch (Exception e) { catch (Exception e) {
log.appendMsg("WARNING: Problem fixing up symbol '%s' - %s" 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 { finally {
program.getRelocationTable() 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."); log.appendMsg("Fixed up " + fixedAddrs.size() + " chained pointers.");

View file

@ -146,7 +146,7 @@ public abstract class AbstractClassicProcessor {
status = Status.UNSUPPORTED; status = Status.UNSUPPORTED;
} }
else { else {
status = Status.APPLIED_OTHER; status = Status.APPLIED;
} }
// put an entry in the relocation table, handled or not // put an entry in the relocation table, handled or not

View file

@ -150,7 +150,7 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
if (entryPoint != null) { if (entryPoint != null) {
Address entryPointAddr = space.getAddress(entryPoint); Address entryPointAddr = space.getAddress(entryPoint);
program.getSymbolTable().addExternalEntryPoint(entryPointAddr); program.getSymbolTable().addExternalEntryPoint(entryPointAddr);
createOneByteFunction("entry", entryPointAddr); createOneByteFunction(program, "entry", entryPointAddr);
} }
else { else {
log.appendMsg("Unable to determine entry point."); log.appendMsg("Unable to determine entry point.");

View file

@ -514,7 +514,7 @@ public class MachoProgramBuilder {
if (!realEntryFound) { if (!realEntryFound) {
program.getSymbolTable().createLabel(addr, "entry", SourceType.IMPORTED); program.getSymbolTable().createLabel(addr, "entry", SourceType.IMPORTED);
program.getSymbolTable().addExternalEntryPoint(addr); program.getSymbolTable().addExternalEntryPoint(addr);
createOneByteFunction("entry", addr); createOneByteFunction(program, "entry", addr);
realEntryFound = true; realEntryFound = true;
} }
else { else {
@ -684,10 +684,11 @@ public class MachoProgramBuilder {
monitor.increment(); monitor.increment();
int symbolIndex = indirectSymbols.get(i); int symbolIndex = indirectSymbols.get(i);
NList symbol = symbolTableCommand.getSymbolAt(symbolIndex); NList symbol = symbolTableCommand.getSymbolAt(symbolIndex);
String name = String name = null;
symbol != null ? SymbolUtilities.replaceInvalidChars(symbol.getString(), true) if (symbol != null) {
: "STUB_" + startAddr; name = SymbolUtilities.replaceInvalidChars(symbol.getString(), true);
Function stubFunc = createOneByteFunction(name, startAddr); }
Function stubFunc = createOneByteFunction(program, name, startAddr);
if (stubFunc != null && symbol != null) { if (stubFunc != null && symbol != null) {
ExternalLocation loc = program.getExternalManager() ExternalLocation loc = program.getExternalManager()
.addExtLocation(Library.UNKNOWN, name, null, SourceType.IMPORTED); .addExtLocation(Library.UNKNOWN, name, null, SourceType.IMPORTED);
@ -965,8 +966,8 @@ public class MachoProgramBuilder {
} }
finally { finally {
program.getRelocationTable() program.getRelocationTable()
.add(addr, success ? Status.APPLIED_OTHER : Status.FAILURE, .add(addr, success ? Status.APPLIED : Status.FAILURE, binding.getType(),
binding.getType(), null, bytes.length, binding.getSymbolName()); null, bytes.length, binding.getSymbolName());
} }
} }
} }
@ -1584,7 +1585,7 @@ public class MachoProgramBuilder {
} }
Register tModeRegister = program.getLanguage().getRegister("TMode"); Register tModeRegister = program.getLanguage().getRegister("TMode");
program.getProgramContext().setValue(tModeRegister, address, address, BigInteger.ONE); program.getProgramContext().setValue(tModeRegister, address, address, BigInteger.ONE);
createOneByteFunction(null, address); createOneByteFunction(program, null, address);
} }
private void processLazyPointerSection(AddressSetView set) { private void processLazyPointerSection(AddressSetView set) {
@ -1638,13 +1639,14 @@ public class MachoProgramBuilder {
* create a one-byte function, so that when the code is analyzed, * create a one-byte function, so that when the code is analyzed,
* it will be disassembled, and the function created with the correct body. * 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 name the name of the function
* @param address location to create the function * @param address location to create the function
* @return If a function already existed at the given address, that function will be returned. * @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 * Otherwise, the newly created function will be returned. If there was a problem creating
* the function, null will be returned. * 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(); FunctionManager functionMgr = program.getFunctionManager();
Function function = functionMgr.getFunctionAt(address); Function function = functionMgr.getFunctionAt(address);
if (function != null) { if (function != null) {

View file

@ -64,9 +64,9 @@ public class MachoProgramUtils {
Address ret; Address ret;
if (externalBlock != null) { if (externalBlock != null) {
ret = externalBlock.getEnd().add(1); 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); mem.join(externalBlock, newBlock);
//joinedBlock.setName(MemoryBlock.EXTERNAL_BLOCK_NAME);
} }
else { else {
ret = MachoProgramUtils.getNextAvailableAddress(program); ret = MachoProgramUtils.getNextAvailableAddress(program);

View file

@ -113,7 +113,7 @@ public class MachoExtractProgramBuilder extends MachoProgramBuilder {
// location to the newly exported function // location to the newly exported function
Function func = funcManager.getFunctionAt(sym.getAddress()); Function func = funcManager.getFunctionAt(sym.getAddress());
if (func != null && func.getThunkedFunction(false) != null) { 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. // Remove the external location associated with the thunk function.
// After the first delete, the external location becomes an external label, which // After the first delete, the external location becomes an external label, which