Better support for Mach-O MH_OBJECTs and archives (fixes #2702)

This commit is contained in:
Ryan Kurtz 2021-02-01 14:18:17 -05:00 committed by ghidra1
parent 6ed341bc87
commit 3bccb8ce65
2 changed files with 47 additions and 15 deletions

View file

@ -23,8 +23,12 @@ import generic.continues.GenericFactory;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.ByteProviderWrapper;
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
import ghidra.app.util.bin.format.coff.CoffException;
import ghidra.app.util.bin.format.coff.archive.CoffArchiveHeader;
import ghidra.app.util.bin.format.coff.archive.CoffArchiveMemberHeader;
import ghidra.app.util.bin.format.macho.MachException;
import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.util.task.TaskMonitor;
/**
* Represents a fat_header structure.
@ -71,9 +75,32 @@ public class FatHeader {
}
for (FatArch fatarch : architectures) {
ByteProviderWrapper wrapper = new ByteProviderWrapper(provider, fatarch.getOffset(), fatarch.getSize());
MachHeader machHeader = MachHeader.createMachHeader(factory, wrapper);
machHeaders.add(machHeader);
ByteProviderWrapper wrapper =
new ByteProviderWrapper(provider, fatarch.getOffset(), fatarch.getSize());
// It could be a Mach-O or a COFF archive
CoffArchiveHeader caf = null;
try {
caf = CoffArchiveHeader.read(wrapper, TaskMonitor.DUMMY);
}
catch (CoffException e) {
throw new UbiException(e);
}
if (caf != null) {
for (CoffArchiveMemberHeader camh : caf.getArchiveMemberHeaders()) {
wrapper = new ByteProviderWrapper(provider,
fatarch.getOffset() + camh.getPayloadOffset(), camh.getSize());
try {
machHeaders.add(MachHeader.createMachHeader(factory, wrapper));
}
catch (MachException e) {
// Could be __.SYMDEF archive member instead of a Mach-O
}
}
}
else {
machHeaders.add(MachHeader.createMachHeader(factory, wrapper));
}
}
}

View file

@ -16,8 +16,7 @@
package ghidra.app.util.opinion;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.bin.ByteProvider;
@ -215,26 +214,32 @@ public class MachoProgramBuilder {
}
// Create memory blocks for segments.
for (SegmentCommand segment : header.getAllSegments()) {
ListIterator<SegmentCommand> it = header.getAllSegments().listIterator();
while (it.hasNext()) {
int i = it.nextIndex();
final SegmentCommand segment = it.next();
if (monitor.isCancelled()) {
break;
}
if (segment.getFileSize() > 0 && (allowZeroAddr || segment.getVMaddress() != 0)) {
if (createMemoryBlock(segment.getSegmentName(),
space.getAddress(segment.getVMaddress()), segment.getFileOffset(),
segment.getFileSize(), segment.getSegmentName(), source, segment.isRead(),
segment.isWrite(), segment.isExecute(), false) == null) {
String segmentName = segment.getSegmentName();
if (segmentName.isBlank()) {
segmentName = "SEGMENT." + i;
}
if (createMemoryBlock(segmentName, space.getAddress(segment.getVMaddress()),
segment.getFileOffset(), segment.getFileSize(), segmentName, source,
segment.isRead(), segment.isWrite(), segment.isExecute(), false) == null) {
log.appendMsg(String.format("Failed to create block: %s 0x%x 0x%x",
segment.getSegmentName(), segment.getVMaddress(), segment.getVMsize()));
}
if (segment.getVMsize() > segment.getFileSize()) {
// Pad the remaining address range with uninitialized data
if (createMemoryBlock(segment.getSegmentName(),
if (createMemoryBlock(segmentName,
space.getAddress(segment.getVMaddress()).add(segment.getFileSize()), 0,
segment.getVMsize() - segment.getFileSize(), segment.getSegmentName(),
source, segment.isRead(), segment.isWrite(), segment.isExecute(),
true) == null) {
segment.getVMsize() - segment.getFileSize(), segmentName, source,
segment.isRead(), segment.isWrite(), segment.isExecute(), true) == null) {
log.appendMsg(String.format("Failed to create block: %s 0x%x 0x%x",
segment.getSegmentName(), segment.getVMaddress(), segment.getVMsize()));
}
@ -1343,7 +1348,7 @@ public class MachoProgramBuilder {
NList nList = machoHeader.getFirstLoadCommand(SymbolTableCommand.class).getSymbolAt(
symbolIndex);
Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(program, nList.getString(),
err -> log.error("Macho", err));
err -> log.appendMsg("Macho", err));
if (relocation.isPcRelocated()) {
destinationAddress = symbol.getAddress().subtractWrap(