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
// 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);
}
else {
@@ -37,23 +37,22 @@ import ghidra.util.task.TaskMonitor;
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 allowFileset True if Mach-O file sets should be considered a PRELINK binary;
* otherwise, false
* @param monitor A monitor
* @return True if the given {@link ByteProvider} is a Mach-O PRELINK binary; otherwise, false
*/
public static boolean isMachoPrelink(ByteProvider provider, boolean allowFileset,
TaskMonitor monitor) {
public static boolean isMachoPrelink(ByteProvider provider, TaskMonitor monitor) {
try {
MachHeader header = new MachHeader(provider);
boolean hasPrelinkSegment = new MachHeader(provider).parseSegments()
.stream()
.anyMatch(segment -> segment.getSegmentName().startsWith("__PRELINK"));
boolean hasFileSet = header.parseAndCheck(LoadCommandTypes.LC_FILESET_ENTRY);
return hasPrelinkSegment && allowFileset && hasFileSet;
return hasPrelinkSegment && !hasFileSet;
}
catch (MachException | IOException e) {
// Assume it's not a Mach-O PRELINK...fall through
@@ -61,6 +60,22 @@ public class MachoPrelinkUtils {
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.
*
@@ -18,9 +18,7 @@ package ghidra.file.formats.ios.fileset;
import java.io.IOException;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.macho.MachException;
import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.app.util.bin.format.macho.commands.LoadCommandTypes;
import ghidra.app.util.opinion.MachoPrelinkUtils;
import ghidra.formats.gfilesystem.FSRLRoot;
import ghidra.formats.gfilesystem.FileSystemService;
import ghidra.formats.gfilesystem.factory.GFileSystemFactoryByteProvider;
@@ -46,12 +44,6 @@ public class MachoFileSetFileSystemFactory implements
@Override
public boolean probe(ByteProvider byteProvider, FileSystemService fsService,
TaskMonitor monitor) throws IOException, CancelledException {
try {
return new MachHeader(byteProvider).parseAndCheck(LoadCommandTypes.LC_FILESET_ENTRY);
}
catch (MachException e) {
// Assume it's not a Mach-O...fall through
}
return false;
return MachoPrelinkUtils.isMachoFileset(byteProvider);
}
}
@@ -75,7 +75,7 @@ public class MachoPrelinkFileSystem extends GFileSystemBase implements GFileSyst
@Override
public boolean isValid(TaskMonitor monitor) throws IOException {
return MachoPrelinkUtils.isMachoPrelink(provider, false, monitor);
return MachoPrelinkUtils.isMachoPrelink(provider, monitor);
}
@Override