mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-24 21:21:56 +00:00
GT-3490 fix reading past EOF in ByteProviders
This commit is contained in:
parent
226e1952cf
commit
4e1b743901
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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]";
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
* <p>
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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<LoadCommand> _commands = new ArrayList<LoadCommand>();
|
||||
private List<LoadCommand> _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<Section> getAllSections() {
|
||||
List<Section> tmp = new ArrayList<Section>();
|
||||
List<Section> tmp = new ArrayList<>();
|
||||
for (SegmentCommand segment : getAllSegments()) {
|
||||
tmp.addAll(segment.getSections());
|
||||
}
|
||||
@ -245,7 +259,7 @@ public class MachHeader implements StructConverter {
|
||||
}
|
||||
|
||||
public <T> List<T> getLoadCommands(Class<T> classType) {
|
||||
List<T> tmp = new ArrayList<T>();
|
||||
List<T> 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);
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class Section implements StructConverter {
|
||||
|
||||
private FactoryBundledWithBinaryReader reader;
|
||||
private boolean is32bit;
|
||||
private List<RelocationInfo> relocations = new ArrayList<RelocationInfo>();
|
||||
private List<RelocationInfo> 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();
|
||||
|
@ -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 List<DebugCOFFSymbol>symbols = new ArrayList<DebugCOFFSymbol>();
|
||||
private List<DebugCOFFSymbol>symbols = 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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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<FileSystemInfoRec> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<byte[]> getImages() {
|
||||
runImageAnalyzer();
|
||||
|
||||
List<byte[]> imageList = new ArrayList<byte[]>();
|
||||
DataIterator it = program.getListing().getDefinedData(true);
|
||||
while (it.hasNext()) {
|
||||
accumulateImageData(imageList, it.next());
|
||||
}
|
||||
return imageList;
|
||||
}
|
||||
|
||||
private void accumulateImageData(List<byte[]> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user