diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveConstants.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveConstants.java index b60f817069d..ce91eb0cc17 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveConstants.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveConstants.java @@ -17,10 +17,7 @@ public final class CoffArchiveConstants { - public final static String MAGIC = "!\n"; - public final static int MAGIC_LEN = MAGIC.length(); - public static final int MAGIC_LEN_CONST_EXPR = 8; + public static final String MAGIC = "!\n"; + public static final int MAGIC_LEN = MAGIC.length(); public static final byte[] MAGIC_BYTES = MAGIC.getBytes(); - - public final static String END_OF_HEADER_MAGIC = "'\n"; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveHeader.java index 807a692bdf4..1e7ccb327a0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveHeader.java @@ -47,8 +47,8 @@ public final class CoffArchiveHeader implements StructConverter { * @throws IOException */ public static boolean isMatch(ByteProvider provider) throws IOException { - return (provider.length() > 2) && CoffArchiveConstants.MAGIC.equals( - new String(provider.readBytes(0, CoffArchiveConstants.MAGIC_LEN))); + return (provider.length() > CoffArchiveConstants.MAGIC_LEN) && CoffArchiveConstants.MAGIC + .equals(new String(provider.readBytes(0, CoffArchiveConstants.MAGIC_LEN))); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ubi/FatHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ubi/FatHeader.java index e2edf0bc870..14b4de0bb7a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ubi/FatHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/ubi/FatHeader.java @@ -23,8 +23,12 @@ 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 @@ private void initFatHeader(GenericFactory factory, ByteProvider provider) throws } 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)); + } } } 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 e77ad1cf8da..8bd52e562da 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 @@ -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 @@ protected void processMemoryBlocks(MachHeader header, String source, boolean pro } // Create memory blocks for segments. - for (SegmentCommand segment : header.getAllSegments()) { + ListIterator 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 @@ private void processSectionRelocation_x86(Section relocationSection, 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( diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/coff/CoffArchiveFileSystemFactory.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/coff/CoffArchiveFileSystemFactory.java index 14b15847887..d8a725f18d8 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/coff/CoffArchiveFileSystemFactory.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/coff/CoffArchiveFileSystemFactory.java @@ -30,7 +30,7 @@ public class CoffArchiveFileSystemFactory implements GFileSystemFactoryFull, GFileSystemProbeBytesOnly { - public static final int PROBE_BYTES_REQUIRED = CoffArchiveConstants.MAGIC_LEN_CONST_EXPR; + public static final int PROBE_BYTES_REQUIRED = CoffArchiveConstants.MAGIC_LEN; @Override public CoffArchiveFileSystem create(FSRL containerFSRL, FSRLRoot targetFSRL,