diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java index a5205d76c5..b0007ee4c8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java @@ -314,7 +314,7 @@ public class BinaryReader { * @exception IOException if an I/O error occurs */ public String readNextNullTerminatedAsciiString() throws IOException { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); while (currentIndex < provider.length()) { byte b = provider.readByte(currentIndex++); if (b == 0) { @@ -430,7 +430,7 @@ public class BinaryReader { * @exception IOException if an I/O error occurs */ public String readAsciiString(long index) throws IOException { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); long len = provider.length(); while (true) { if (index == len) { @@ -459,7 +459,7 @@ public class BinaryReader { * @exception IOException if an I/O error occurs */ public String readAsciiString(long index, int length) throws IOException { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); for (int i = 0; i < length; ++i) { byte b = provider.readByte(index++); buffer.append((char) (b & 0x00FF)); @@ -479,7 +479,7 @@ public class BinaryReader { * @exception IOException if an I/O error occurs */ public String readTerminatedString(long index, char termChar) throws IOException { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); long len = provider.length(); while (index < len) { char c = (char) provider.readByte(index++); @@ -503,7 +503,7 @@ public class BinaryReader { * @exception IOException if an I/O error occurs */ public String readTerminatedString(long index, String termChars) throws IOException { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); long len = provider.length(); while (index < len) { char c = (char) provider.readByte(index++); @@ -544,7 +544,7 @@ public class BinaryReader { * @exception IOException if an I/O error occurs */ public String readUnicodeString(long index) throws IOException { - StringBuffer buffer = new StringBuffer(); + StringBuilder buffer = new StringBuilder(); while (index < length()) { int ch = readUnsignedShort(index); if (ch == 0) { @@ -571,7 +571,7 @@ public class BinaryReader { * @exception IOException if an I/O error occurs */ public String readUnicodeString(long index, int length) throws IOException { - StringBuffer buffer = new StringBuffer(length); + StringBuilder buffer = new StringBuilder(length); long endOffset = index + (length * 2); while (index < endOffset) { int ch = readUnsignedShort(index); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/GhidraRandomAccessFile.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/GhidraRandomAccessFile.java index 0b590237c0..1bd09b64fc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/GhidraRandomAccessFile.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/GhidraRandomAccessFile.java @@ -27,7 +27,7 @@ import ghidra.util.Msg; * This implementation relies on java.net.RandomAccessFile, * but adds buffering to limit the amount. */ -public class GhidraRandomAccessFile { +public class GhidraRandomAccessFile implements AutoCloseable { private static final byte[] EMPTY = new byte[0]; private static final int BUFFER_SIZE = 0x100000; @@ -112,6 +112,7 @@ public class GhidraRandomAccessFile { * If this file has an associated channel then the channel is closed as well. * @exception IOException if an I/O error occurs. */ + @Override public void close() throws IOException { checkOpen(); open = false; @@ -291,8 +292,11 @@ public class GhidraRandomAccessFile { buffer = new byte[BUFFER_SIZE]; randomAccessFile.seek(bufferFileStartIndex); - randomAccessFile.read(buffer); + int bytesRead = randomAccessFile.read(buffer); bufferOffset = 0; + if (bytesRead <= 0) { + throw new EOFException(); + } } else { bufferOffset = newBufferOffset; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/RandomAccessByteProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/RandomAccessByteProvider.java index 2bace5bf3d..403b27d0ec 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/RandomAccessByteProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/RandomAccessByteProvider.java @@ -18,6 +18,7 @@ package ghidra.app.util.bin; import java.io.*; import ghidra.formats.gfilesystem.FSRL; +import ghidra.util.Msg; /** * An implementation of ByteProvider where the underlying @@ -33,15 +34,15 @@ public class RandomAccessByteProvider implements ByteProvider { protected File file; protected GhidraRandomAccessFile randomAccessFile; private FSRL fsrl; - private Long cachedLength; + private long fileLength; /** * Constructs a {@link ByteProvider} using the specified {@link File}. * * @param file the {@link File} to open for random access - * @throws FileNotFoundException if the {@link File} does not exist + * @throws IOException if the {@link File} does not exist or other error */ - public RandomAccessByteProvider(File file) throws FileNotFoundException { + public RandomAccessByteProvider(File file) throws IOException { this(file, "r"); } @@ -50,11 +51,10 @@ public class RandomAccessByteProvider implements ByteProvider { * * @param file the {@link File} to open for random access * @param fsrl the {@link FSRL} to use for the {@link File}'s path - * @throws FileNotFoundException if the {@link File} does not exist + * @throws IOException if the {@link File} does not exist or other error */ - public RandomAccessByteProvider(File file, FSRL fsrl) throws FileNotFoundException { - this(file, "r"); - this.fsrl = fsrl; + public RandomAccessByteProvider(File file, FSRL fsrl) throws IOException { + this(file, fsrl, "r"); } /** @@ -62,11 +62,17 @@ public class RandomAccessByteProvider implements ByteProvider { * * @param file the {@link File} to open for random access * @param permissions indicating permissions used for open - * @throws FileNotFoundException if the {@link File} does not exist + * @throws IOException if the {@link File} does not exist or other error */ - public RandomAccessByteProvider(File file, String permissions) throws FileNotFoundException { + public RandomAccessByteProvider(File file, String permissions) throws IOException { + this(file, null, permissions); + } + + private RandomAccessByteProvider(File file, FSRL fsrl, String permissions) throws IOException { this.file = file; + this.fsrl = fsrl; this.randomAccessFile = new GhidraRandomAccessFile(file, permissions); + this.fileLength = randomAccessFile.length(); } @Override @@ -111,21 +117,13 @@ public class RandomAccessByteProvider implements ByteProvider { } @Override - public long length() throws IOException { - if (cachedLength == null) { - cachedLength = randomAccessFile.length(); - } - return cachedLength; + public long length() { + return fileLength; } @Override public boolean isValidIndex(long index) { - try { - return index >= 0 && index < length(); - } - catch (IOException e) { - return false; - } + return 0 <= index && index < fileLength; } @Override @@ -136,12 +134,27 @@ public class RandomAccessByteProvider implements ByteProvider { @Override public byte[] readBytes(long index, long length) throws IOException { - randomAccessFile.seek(index); byte[] b = new byte[(int) length]; + if (index > fileLength) { + throw new EOFException( + "Invalid file offset " + index + " while reading " + file.getName()); + } + if (index + length > fileLength) { + Msg.trace(this, "Read at EOF, can't return partial buffer, throwing IOException: " + + file.getName()); + throw new EOFException("EOF: unable to read " + length + " bytes at " + index); + } + randomAccessFile.seek(index); int nRead = randomAccessFile.read(b); if (nRead != length) { throw new IOException("Unable to read " + length + " bytes"); } return b; } + + @Override + public String toString() { + return "RandomAccessByteProvider [\n file=" + file + ",\n fsrl=" + fsrl + + ",\n fileLength=" + fileLength + "\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 51b8468cc8..807a692bdf 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 @@ -15,16 +15,17 @@ */ package ghidra.app.util.bin.format.coff.archive; -import ghidra.app.util.bin.*; -import ghidra.app.util.bin.format.coff.CoffException; -import ghidra.program.model.data.*; -import ghidra.util.exception.DuplicateNameException; -import ghidra.util.task.TaskMonitor; - import java.io.IOException; import java.util.ArrayList; import java.util.List; +import ghidra.app.util.bin.*; +import ghidra.app.util.bin.format.coff.CoffException; +import ghidra.program.model.data.*; +import ghidra.util.Msg; +import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; + /** * A class that represents a COFF archive file (ie. MS .lib files, Unix .ar files) *

@@ -74,39 +75,54 @@ public final class CoffArchiveHeader implements StructConverter { CoffArchiveHeader cah = new CoffArchiveHeader(); - while (reader.getPointerIndex() < reader.length() - 1) { + long eofPos = reader.length() - CoffArchiveMemberHeader.CAMH_MIN_SIZE; + + while (reader.getPointerIndex() < eofPos) { if (monitor.isCancelled()) { break; } - CoffArchiveMemberHeader camh = - CoffArchiveMemberHeader.read(reader, cah._longNameMember); + try { + CoffArchiveMemberHeader camh = + CoffArchiveMemberHeader.read(reader, cah._longNameMember); - if (camh.getName().equals(CoffArchiveMemberHeader.SLASH)) { - switch (memberNum) { - case 0: - cah._firstLinkerMember = new FirstLinkerMember(reader, camh, true); - break; - case 1: - cah._secondLinkerMember = new SecondLinkerMember(reader, camh, true); - break; - default: + if (camh.getName().equals(CoffArchiveMemberHeader.SLASH)) { + switch (memberNum) { + case 0: + cah._firstLinkerMember = new FirstLinkerMember(reader, camh, true); + break; + case 1: + cah._secondLinkerMember = new SecondLinkerMember(reader, camh, true); + break; + default: + throw new CoffException( + "Invalid COFF: multiple 1st and 2nd linker members detected."); + } + } + else if (camh.getName().equals(CoffArchiveMemberHeader.SLASH_SLASH)) { + if (cah._longNameMember == null) { + cah._longNameMember = new LongNamesMember(reader, camh); + } + else { throw new CoffException( - "Invalid COFF: multiple 1st and 2nd linker members detected."); + "Invalid COFF: multiple long name members detected."); + } } - } - else if (camh.getName().equals(CoffArchiveMemberHeader.SLASH_SLASH)) { - if (cah._longNameMember == null) { - cah._longNameMember = new LongNamesMember(reader, camh); - } - else { - throw new CoffException("Invalid COFF: multiple long name members detected."); - } - } - cah._memberHeaders.add(camh); - memberNum++; + cah._memberHeaders.add(camh); + memberNum++; - reader.setPointerIndex(camh.getPayloadOffset() + camh.getSize()); + reader.setPointerIndex(camh.getPayloadOffset() + camh.getSize()); + } + catch (IOException e) { + // if we run into bad data, return partial success if there has been at least some + // good ones, otherwise propagate the exception upwards + if (memberNum <= 3) { + throw e; + } + Msg.warn(CoffArchiveMemberHeader.class, "Problem reading COFF archive headers in " + + provider.getFSRL() + ", only " + memberNum + " members found.", e); + break; + } } // TODO: check for null terminators in the longname string table vs. \n terminators @@ -125,6 +141,7 @@ public final class CoffArchiveHeader implements StructConverter { protected CoffArchiveHeader() { } + @Override public DataType toDataType() throws DuplicateNameException, IOException { Structure struct = new StructureDataType(StructConverterUtil.parseName(CoffArchiveHeader.class), 0); struct.add(STRING, CoffArchiveConstants.MAGIC_LEN, "magic", null); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveMemberHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveMemberHeader.java index 301b6c14cc..08b4e3a7d1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveMemberHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveMemberHeader.java @@ -50,6 +50,7 @@ public class CoffArchiveMemberHeader implements StructConverter { private static final String CAMH_EOH_MAGIC = "`\n"; private static final int CAMH_PAYLOAD_OFF = 60; + public static final int CAMH_MIN_SIZE = CAMH_PAYLOAD_OFF; /** * Reads a COFF archive member header from the specified {@link BinaryReader reader}, @@ -162,8 +163,9 @@ public class CoffArchiveMemberHeader implements StructConverter { try { long offset = Long.parseLong(name.substring(1)); name = longNames.getStringAtOffset(reader.getByteProvider(), offset); - if (name.endsWith("/")) + if (name.endsWith("/")) { name = name.substring(0, name.length() - 1); + } } catch (NumberFormatException nfe) { throw new IOException("Bad long name offset: " + name); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachConstants.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachConstants.java index b5a0a045b3..2020b14081 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachConstants.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachConstants.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachHeader.java index 2ed68b7a0f..4cda38ae83 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/MachHeader.java @@ -16,13 +16,11 @@ package ghidra.app.util.bin.format.macho; import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; import generic.continues.GenericFactory; -import ghidra.app.util.bin.ByteProvider; -import ghidra.app.util.bin.StructConverter; +import ghidra.app.util.bin.*; import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader; import ghidra.app.util.bin.format.macho.commands.*; import ghidra.program.model.data.*; @@ -44,12 +42,28 @@ public class MachHeader implements StructConverter { private int reserved;//only used in 64-bit private boolean _is32bit; - private List _commands = new ArrayList(); + private List _commands = new ArrayList<>(); private long _commandIndex; private FactoryBundledWithBinaryReader _reader; private long _machHeaderStartIndexInProvider; private boolean _parsed = false; + /** + * Returns true if the specified ByteProvider starts with a Mach header magic signature. + * + * @param provider {@link ByteProvider} to check + * @return boolean true if byte provider starts with a MachHeader + */ + public static boolean isMachHeader(ByteProvider provider) { + try { + return provider.length() > Integer.BYTES && + MachConstants.isMagic(readMagic(provider, 0)); + } + catch (IOException e) { + // dont care + } + return false; + } /** * Assumes the MachHeader starts at index 0 in the ByteProvider. * @param provider the ByteProvider @@ -233,7 +247,7 @@ public class MachHeader implements StructConverter { } public List

getAllSections() { - List
tmp = new ArrayList
(); + List
tmp = new ArrayList<>(); for (SegmentCommand segment : getAllSegments()) { tmp.addAll(segment.getSections()); } @@ -245,7 +259,7 @@ public class MachHeader implements StructConverter { } public List getLoadCommands(Class classType) { - List tmp = new ArrayList(); + List tmp = new ArrayList<>(); for (LoadCommand command : _commands) { if (classType.isAssignableFrom(command.getClass())) { tmp.add(classType.cast(command)); @@ -282,22 +296,14 @@ public class MachHeader implements StructConverter { return buffer.toString(); } - public InputStream getDataStream() throws IOException { - return _reader.getByteProvider().getInputStream(0); - } - @Override public String toString() { return getDescription(); } - private int readMagic(ByteProvider provider, long machHeaderStartIndexInProvider) + private static int readMagic(ByteProvider provider, long machHeaderStartIndexInProvider) throws IOException { - int value = 0; - value |= (provider.readByte(machHeaderStartIndexInProvider + 0) << 0x18) & 0xff000000; - value |= (provider.readByte(machHeaderStartIndexInProvider + 1) << 0x10) & 0x00ff0000; - value |= (provider.readByte(machHeaderStartIndexInProvider + 2) << 0x08) & 0x0000ff00; - value |= (provider.readByte(machHeaderStartIndexInProvider + 3) << 0x00) & 0x000000ff; - return value; + BinaryReader br = new BinaryReader(provider, false); + return br.readInt(machHeaderStartIndexInProvider); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/Section.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/Section.java index 048f93067b..6ce95f2ee2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/Section.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/Section.java @@ -48,7 +48,7 @@ public class Section implements StructConverter { private FactoryBundledWithBinaryReader reader; private boolean is32bit; - private List relocations = new ArrayList(); + private List relocations = new ArrayList<>(); public static Section createSection(FactoryBundledWithBinaryReader reader, boolean is32bit) throws IOException { @@ -71,8 +71,8 @@ public class Section implements StructConverter { sectname = reader.readNextAsciiString(MachConstants.NAME_LENGTH); segname = reader.readNextAsciiString(MachConstants.NAME_LENGTH); if (is32bit) { - addr = reader.readNextInt() & 0xffffffffL; - size = reader.readNextInt() & 0xffffffffL; + addr = reader.readNextUnsignedInt(); + size = reader.readNextUnsignedInt(); } else { addr = reader.readNextLong(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/FileHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/FileHeader.java index 053e316505..2a9cfebdd2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/FileHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/FileHeader.java @@ -15,7 +15,8 @@ */ package ghidra.app.util.bin.format.pe; -import java.io.*; +import java.io.IOException; +import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.List; @@ -144,7 +145,7 @@ public class FileHeader implements StructConverter { private short characteristics; private SectionHeader [] sectionHeaders; - private Listsymbols = new ArrayList(); + private Listsymbols = new ArrayList<>(); private FactoryBundledWithBinaryReader reader; private int startIndex; @@ -560,8 +561,4 @@ public class FileHeader implements StructConverter { } return PortableExecutable.computeAlignment( lastPos, optionalHeader.getFileAlignment( ) ); } - - public InputStream getDataStream() throws IOException { - return reader.getByteProvider().getInputStream(0); - } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java index c28e63056a..8e8fd41acc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoLoader.java @@ -94,6 +94,9 @@ public class MachoLoader extends AbstractLibrarySupportLoader { MachoProgramBuilder.buildProgram(program, provider, fileBytes, log, monitor); } } + catch (IOException e) { + throw e; + } catch (Exception e) { throw new IOException(e.getMessage()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemFactoryMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemFactoryMgr.java index cf35f99748..e9ca6e4f7c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemFactoryMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/formats/gfilesystem/factory/FileSystemFactoryMgr.java @@ -212,27 +212,35 @@ public class FileSystemFactoryMgr { try (ByteProvider bp = new RandomAccessByteProvider(containerFile, containerFSRL)) { byte[] startBytes = bp.readBytes(0, pboByteCount); for (FileSystemInfoRec fsir : sortedFactories) { - if (fsir.getFactory() instanceof GFileSystemProbeBytesOnly) { - GFileSystemProbeBytesOnly factoryProbe = - (GFileSystemProbeBytesOnly) fsir.getFactory(); - if (factoryProbe.getBytesRequired() <= startBytes.length) { - if (factoryProbe.probeStartBytes(containerFSRL, startBytes)) { + try { + if (fsir.getFactory() instanceof GFileSystemProbeBytesOnly) { + GFileSystemProbeBytesOnly factoryProbe = + (GFileSystemProbeBytesOnly) fsir.getFactory(); + if (factoryProbe.getBytesRequired() <= startBytes.length) { + if (factoryProbe.probeStartBytes(containerFSRL, startBytes)) { + return true; + } + } + } + if (fsir.getFactory() instanceof GFileSystemProbeWithFile) { + GFileSystemProbeWithFile factoryProbe = + (GFileSystemProbeWithFile) fsir.getFactory(); + if (factoryProbe.probe(containerFSRL, containerFile, fsService, monitor)) { + return true; + } + } + if (fsir.getFactory() instanceof GFileSystemProbeFull) { + GFileSystemProbeFull factoryProbe = + (GFileSystemProbeFull) fsir.getFactory(); + if (factoryProbe.probe(containerFSRL, bp, containerFile, fsService, + monitor)) { return true; } } } - if (fsir.getFactory() instanceof GFileSystemProbeWithFile) { - GFileSystemProbeWithFile factoryProbe = - (GFileSystemProbeWithFile) fsir.getFactory(); - if (factoryProbe.probe(containerFSRL, containerFile, fsService, monitor)) { - return true; - } - } - if (fsir.getFactory() instanceof GFileSystemProbeFull) { - GFileSystemProbeFull factoryProbe = (GFileSystemProbeFull) fsir.getFactory(); - if (factoryProbe.probe(containerFSRL, bp, containerFile, fsService, monitor)) { - return true; - } + catch (IOException e) { + Msg.trace(this, "File system probe error for " + fsir.getDescription() + + " with " + containerFSRL, e); } } } @@ -303,34 +311,41 @@ public class FileSystemFactoryMgr { byte[] startBytes = probeBP.readBytes(0, pboByteCount); List probeMatches = new ArrayList<>(); for (FileSystemInfoRec fsir : sortedFactories) { - if (fsir.getPriority() < priorityFilter) { - break; - } - if (fsir.getFactory() instanceof GFileSystemProbeBytesOnly) { - GFileSystemProbeBytesOnly factoryProbe = - (GFileSystemProbeBytesOnly) fsir.getFactory(); - if (factoryProbe.getBytesRequired() <= startBytes.length) { - if (factoryProbe.probeStartBytes(containerFSRL, startBytes)) { + try { + if (fsir.getPriority() < priorityFilter) { + break; + } + if (fsir.getFactory() instanceof GFileSystemProbeBytesOnly) { + GFileSystemProbeBytesOnly factoryProbe = + (GFileSystemProbeBytesOnly) fsir.getFactory(); + if (factoryProbe.getBytesRequired() <= startBytes.length) { + if (factoryProbe.probeStartBytes(containerFSRL, startBytes)) { + probeMatches.add(fsir); + continue; + } + } + } + if (fsir.getFactory() instanceof GFileSystemProbeWithFile) { + GFileSystemProbeWithFile factoryProbe = + (GFileSystemProbeWithFile) fsir.getFactory(); + if (factoryProbe.probe(containerFSRL, containerFile, fsService, monitor)) { + probeMatches.add(fsir); + continue; + } + } + if (fsir.getFactory() instanceof GFileSystemProbeFull) { + GFileSystemProbeFull factoryProbe = + (GFileSystemProbeFull) fsir.getFactory(); + if (factoryProbe.probe(containerFSRL, probeBP, containerFile, fsService, + monitor)) { probeMatches.add(fsir); continue; } } } - if (fsir.getFactory() instanceof GFileSystemProbeWithFile) { - GFileSystemProbeWithFile factoryProbe = - (GFileSystemProbeWithFile) fsir.getFactory(); - if (factoryProbe.probe(containerFSRL, containerFile, fsService, monitor)) { - probeMatches.add(fsir); - continue; - } - } - if (fsir.getFactory() instanceof GFileSystemProbeFull) { - GFileSystemProbeFull factoryProbe = (GFileSystemProbeFull) fsir.getFactory(); - if (factoryProbe.probe(containerFSRL, probeBP, containerFile, fsService, - monitor)) { - probeMatches.add(fsir); - continue; - } + catch (IOException e) { + Msg.trace(this, "File system probe error for " + fsir.getDescription() + + " with " + containerFSRL, e); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/examiner/ProgramExaminer.java b/Ghidra/Features/Base/src/main/java/ghidra/program/examiner/ProgramExaminer.java deleted file mode 100644 index 7435a1b8b5..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/examiner/ProgramExaminer.java +++ /dev/null @@ -1,231 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.program.examiner; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import ghidra.GhidraException; -import ghidra.GhidraTestApplicationLayout; -import ghidra.app.plugin.core.analysis.EmbeddedMediaAnalyzer; -import ghidra.app.util.bin.*; -import ghidra.app.util.importer.AutoImporter; -import ghidra.app.util.importer.MessageLog; -import ghidra.framework.Application; -import ghidra.framework.HeadlessGhidraApplicationConfiguration; -import ghidra.program.model.data.*; -import ghidra.program.model.lang.*; -import ghidra.program.model.listing.*; -import ghidra.program.model.mem.MemoryAccessException; -import ghidra.program.util.DefaultLanguageService; -import ghidra.util.exception.CancelledException; -import ghidra.util.task.TaskMonitorAdapter; -import utility.application.ApplicationLayout; - -/** - * Wrapper for Ghidra code to find images (and maybe other artifacts later) in a program - * - */ -public class ProgramExaminer { - - private MessageLog messageLog; - private Program program; - - private static Language defaultLanguage; - - /** - * Constructs a new ProgramExaminer. - * @param bytes the bytes of the potential program to be examined. - * @throws GhidraException if any exception occurs while processing the bytes. - */ - public ProgramExaminer(byte[] bytes) throws GhidraException { - this(createByteProvider(bytes)); - } - - /** - * Constructs a new ProgramExaminer. - * @param file file object containing the bytes to be examined. - * @throws GhidraException if any exception occurs while processing the bytes. - */ - public ProgramExaminer(File file) throws GhidraException { - this(createByteProvider(file)); - } - - /** - * Returns a string indication the program format. i.e. PE, elf, raw - */ - public String getType() { - return program.getExecutableFormat(); - } - - private ProgramExaminer(ByteProvider provider) throws GhidraException { - initializeGhidra(); - messageLog = new MessageLog(); - try { - program = - AutoImporter.importByUsingBestGuess(provider, null, this, messageLog, - TaskMonitorAdapter.DUMMY_MONITOR); - - if (program == null) { - program = - AutoImporter.importAsBinary(provider, null, defaultLanguage, null, this, - messageLog, TaskMonitorAdapter.DUMMY_MONITOR); - } - if (program == null) { - throw new GhidraException("Can't create program from input: " + - messageLog.toString()); - } - } - catch (Exception e) { - messageLog.appendException(e); - throw new GhidraException(e); - } - finally { - try { - provider.close(); - } - catch (IOException e) { - // tried to close - } - } - } - - public synchronized static void initializeGhidra() throws GhidraException { - if (!Application.isInitialized()) { - ApplicationLayout layout; - try { - layout = - new GhidraTestApplicationLayout(new File(System.getProperty("java.io.tmpdir"))); - } - catch (IOException e) { - throw new GhidraException(e); - } - HeadlessGhidraApplicationConfiguration config = - new HeadlessGhidraApplicationConfiguration(); - config.setInitializeLogging(false); - Application.initializeApplication(layout, config); - } - if (defaultLanguage == null) { - LanguageService languageService = DefaultLanguageService.getLanguageService(); - try { - defaultLanguage = languageService.getDefaultLanguage( - Processor.findOrPossiblyCreateProcessor("DATA")); - } - catch (LanguageNotFoundException e) { - throw new GhidraException("Can't load default language: DATA"); - } - } - } - - /** - * Releases file/database resources. - */ - public void dispose() { - program.release(this); - } - - /** - * Returns a list of byte[] containing image data. The bytes will be either a png, a gif, or - * a bitmap - */ - public List getImages() { - runImageAnalyzer(); - - List imageList = new ArrayList(); - DataIterator it = program.getListing().getDefinedData(true); - while (it.hasNext()) { - accumulateImageData(imageList, it.next()); - } - return imageList; - } - - private void accumulateImageData(List imageList, Data data) { - if (!isImage(data)) { - return; - } - - try { - imageList.add(data.getBytes()); - } - catch (MemoryAccessException e) { - // suppress (this shouldn't happen - } - } - - private void runImageAnalyzer() { - int txID = program.startTransaction("find images"); - try { - EmbeddedMediaAnalyzer imageAnalyzer = new EmbeddedMediaAnalyzer(); - imageAnalyzer.added(program, program.getMemory(), TaskMonitorAdapter.DUMMY_MONITOR, - messageLog); - } - catch (CancelledException e) { - // using Dummy, can't happen - } - finally { - program.endTransaction(txID, true); - } - } - - private boolean isImage(Data data) { - DataType dataType = data.getDataType(); - if (dataType instanceof PngDataType) { - return true; - } - if (dataType instanceof GifDataType) { - return true; - } - if (dataType instanceof BitmapResourceDataType) { - return true; - } - if (dataType instanceof IconResourceDataType) { - return true; - } - if (dataType instanceof JPEGDataType) { - return true; - } - return false; - } - -//================================================================================================== -// static methods -//================================================================================================== - - private static ByteProvider createByteProvider(byte[] bytes) throws GhidraException { - if (bytes == null) { - throw new GhidraException("Attempted to process a null byte[]."); - } - if (bytes.length == 0) { - throw new GhidraException("Attempted to process an empty byte[]."); - } - return new ByteArrayProvider("Bytes", bytes); - } - - private static ByteProvider createByteProvider(File file) throws GhidraException { - if (file == null) { - throw new GhidraException("Attempted to process a null file"); - } - try { - return new RandomAccessByteProvider(file); - } - catch (IOException e) { - throw new GhidraException(e); - } - } - -} diff --git a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/prelink/PrelinkFileSystem.java b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/prelink/PrelinkFileSystem.java index 20a03abf34..2ec66e6462 100644 --- a/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/prelink/PrelinkFileSystem.java +++ b/Ghidra/Features/FileFormats/src/main/java/ghidra/file/formats/ios/prelink/PrelinkFileSystem.java @@ -76,7 +76,8 @@ public class PrelinkFileSystem extends GFileSystemBase implements GFileSystemPro @Override public boolean isValid(TaskMonitor monitor) throws IOException { try { - return !MachoPrelinkUtils.parsePrelinkXml(provider, monitor).isEmpty(); + return MachHeader.isMachHeader(provider) && + !MachoPrelinkUtils.parsePrelinkXml(provider, monitor).isEmpty(); } catch (JDOMException e) { Msg.warn(this, e.getMessage());