GP-3770: Fixing Mach-o PRELINK check

This commit is contained in:
Ryan Kurtz
2024-03-25 07:21:53 -04:00
parent b30cf1089f
commit 1fa3fb4f1d
4 changed files with 26 additions and 18 deletions
@@ -90,7 +90,8 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
// A Mach-O file may contain PRELINK information. If so, we use a special // A Mach-O file may contain PRELINK information. If so, we use a special
// program builder that knows how to deal with it. // program builder that knows how to deal with it.
if (MachoPrelinkUtils.isMachoPrelink(provider, true, monitor)) { if (MachoPrelinkUtils.isMachoPrelink(provider, monitor) ||
MachoPrelinkUtils.isMachoFileset(provider)) {
MachoPrelinkProgramBuilder.buildProgram(program, provider, fileBytes, log, monitor); MachoPrelinkProgramBuilder.buildProgram(program, provider, fileBytes, log, monitor);
} }
else { else {
@@ -37,23 +37,22 @@ import ghidra.util.task.TaskMonitor;
public class MachoPrelinkUtils { public class MachoPrelinkUtils {
/** /**
* Check to see if the given {@link ByteProvider} is a Mach-O PRELINK binary * Check to see if the given {@link ByteProvider} is a Mach-O PRELINK binary.
* <p>
* NOTE: This method will return false if the binary is a Mach-O file set.
* *
* @param provider The {@link ByteProvider} to check * @param provider The {@link ByteProvider} to check
* @param allowFileset True if Mach-O file sets should be considered a PRELINK binary;
* otherwise, false
* @param monitor A monitor * @param monitor A monitor
* @return True if the given {@link ByteProvider} is a Mach-O PRELINK binary; otherwise, false * @return True if the given {@link ByteProvider} is a Mach-O PRELINK binary; otherwise, false
*/ */
public static boolean isMachoPrelink(ByteProvider provider, boolean allowFileset, public static boolean isMachoPrelink(ByteProvider provider, TaskMonitor monitor) {
TaskMonitor monitor) {
try { try {
MachHeader header = new MachHeader(provider); MachHeader header = new MachHeader(provider);
boolean hasPrelinkSegment = new MachHeader(provider).parseSegments() boolean hasPrelinkSegment = new MachHeader(provider).parseSegments()
.stream() .stream()
.anyMatch(segment -> segment.getSegmentName().startsWith("__PRELINK")); .anyMatch(segment -> segment.getSegmentName().startsWith("__PRELINK"));
boolean hasFileSet = header.parseAndCheck(LoadCommandTypes.LC_FILESET_ENTRY); boolean hasFileSet = header.parseAndCheck(LoadCommandTypes.LC_FILESET_ENTRY);
return hasPrelinkSegment && allowFileset && hasFileSet; return hasPrelinkSegment && !hasFileSet;
} }
catch (MachException | IOException e) { catch (MachException | IOException e) {
// Assume it's not a Mach-O PRELINK...fall through // Assume it's not a Mach-O PRELINK...fall through
@@ -61,6 +60,22 @@ public class MachoPrelinkUtils {
return false; return false;
} }
/**
* Check to see if the given {@link ByteProvider} is a Mach-O file set
*
* @param provider The {@link ByteProvider} to check
* @return True if the given {@link ByteProvider} is a Mach-O file set; otherwise, false
*/
public static boolean isMachoFileset(ByteProvider provider) {
try {
return new MachHeader(provider).parseAndCheck(LoadCommandTypes.LC_FILESET_ENTRY);
}
catch (MachException | IOException e) {
// Assume it's not a Mach-O file set...fall through
}
return false;
}
/** /**
* Parses the provider looking for PRELINK XML. * Parses the provider looking for PRELINK XML.
* *
@@ -18,9 +18,7 @@ package ghidra.file.formats.ios.fileset;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.macho.MachException; import ghidra.app.util.opinion.MachoPrelinkUtils;
import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.app.util.bin.format.macho.commands.LoadCommandTypes;
import ghidra.formats.gfilesystem.FSRLRoot; import ghidra.formats.gfilesystem.FSRLRoot;
import ghidra.formats.gfilesystem.FileSystemService; import ghidra.formats.gfilesystem.FileSystemService;
import ghidra.formats.gfilesystem.factory.GFileSystemFactoryByteProvider; import ghidra.formats.gfilesystem.factory.GFileSystemFactoryByteProvider;
@@ -46,12 +44,6 @@ public class MachoFileSetFileSystemFactory implements
@Override @Override
public boolean probe(ByteProvider byteProvider, FileSystemService fsService, public boolean probe(ByteProvider byteProvider, FileSystemService fsService,
TaskMonitor monitor) throws IOException, CancelledException { TaskMonitor monitor) throws IOException, CancelledException {
try { return MachoPrelinkUtils.isMachoFileset(byteProvider);
return new MachHeader(byteProvider).parseAndCheck(LoadCommandTypes.LC_FILESET_ENTRY);
}
catch (MachException e) {
// Assume it's not a Mach-O...fall through
}
return false;
} }
} }
@@ -75,7 +75,7 @@ public class MachoPrelinkFileSystem extends GFileSystemBase implements GFileSyst
@Override @Override
public boolean isValid(TaskMonitor monitor) throws IOException { public boolean isValid(TaskMonitor monitor) throws IOException {
return MachoPrelinkUtils.isMachoPrelink(provider, false, monitor); return MachoPrelinkUtils.isMachoPrelink(provider, monitor);
} }
@Override @Override