GP-2052: Improving PrelinkFileSystem isValid() so it doesn't fully

parse the entire Mach-O
This commit is contained in:
Ryan Kurtz 2022-05-20 05:49:55 -04:00
parent 126a4bd5fc
commit 9cf8c84129
3 changed files with 51 additions and 18 deletions

View file

@ -139,11 +139,12 @@ public class MachHeader implements StructConverter {
if (_parsed) {
return this;
}
long currentIndex = _commandIndex;
for (int i = 0; i < nCmds; ++i) {
_reader.setPointerIndex(_commandIndex);
_reader.setPointerIndex(currentIndex);
LoadCommand lc = LoadCommandTypes.getLoadCommand(_reader, this);
_commands.add(lc);
_commandIndex += lc.getCommandSize();
currentIndex += lc.getCommandSize();
}
_parsed = true;
return this;
@ -289,6 +290,15 @@ public class MachHeader implements StructConverter {
return magic == MachConstants.MH_CIGAM || magic == MachConstants.MH_CIGAM_64;
}
/**
* Gets the size of this {@link MachHeader} in bytes
*
* @return The size of this {@link MachHeader} in bytes
*/
public long getSize() {
return _commandIndex - _machHeaderStartIndexInProvider;
}
public String getDescription() {//TODO
StringBuffer buffer = new StringBuffer();
buffer.append("Magic: 0x" + Integer.toHexString(magic));

View file

@ -22,8 +22,7 @@ import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualHashBidiMap;
import org.jdom.JDOMException;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.ByteProviderWrapper;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.macho.MachException;
import ghidra.app.util.bin.format.macho.MachHeader;
import ghidra.app.util.bin.format.macho.commands.*;
@ -36,6 +35,42 @@ import ghidra.util.task.TaskMonitor;
*/
public class MachoPrelinkUtils {
/**
* Check to see if the given {@link ByteProvider} is a Mach-O PRELINK binary
*
* @param provider The {@link ByteProvider} to check
* @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, TaskMonitor monitor) {
try {
MachHeader header = new MachHeader(provider);
BinaryReader reader = new BinaryReader(provider, header.isLittleEndian());
reader.setPointerIndex(header.getSize());
// Doing a full header parse is too slow...we really just need to see if a segment
// exists that starts with __PRELINK. Parse the minimal amount to do that check.
for (int i = 0; i < header.getNumberOfCommands(); i++) {
int type = reader.peekNextInt();
if (type == LoadCommandTypes.LC_SEGMENT || type == LoadCommandTypes.LC_SEGMENT_64) {
SegmentCommand segment = new SegmentCommand(reader, header.is32bit());
if (segment.getSegmentName().startsWith("__PRELINK")) {
return true;
}
}
else {
type = reader.readNextInt();
int size = reader.readNextInt();
reader.setPointerIndex(reader.getPointerIndex() + size - 8);
}
}
}
catch (MachException | IOException e) {
// Assume it's not a Mach-O PRELINK...fall through
}
return false;
}
/**
* Parses the provider looking for PRELINK XML.
*

View file

@ -15,10 +15,9 @@
*/
package ghidra.file.formats.ios.prelink;
import java.util.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import org.apache.commons.collections4.BidiMap;
import org.jdom.JDOMException;
@ -76,18 +75,7 @@ public class PrelinkFileSystem extends GFileSystemBase implements GFileSystemPro
@Override
public boolean isValid(TaskMonitor monitor) throws IOException {
try {
return MachHeader.isMachHeader(provider) &&
!MachoPrelinkUtils.parsePrelinkXml(provider, monitor).isEmpty();
}
catch (JDOMException e) {
Msg.warn(this, e.getMessage());
return true; // use KModInfo technique to open
}
catch (IOException e) {
Msg.warn(this, e.getMessage());
return false;
}
return MachoPrelinkUtils.isMachoPrelink(provider, monitor);
}
@Override