mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-907 Add getByteProvider(GFile) to some file systems.
This commit adds getByteProvider(GFile) to a first batch of filesystems. Remaining filesystems will be addressed in future commits.
This commit is contained in:
parent
f91ba90fe8
commit
3c73f252cb
15 changed files with 403 additions and 202 deletions
|
@ -17,6 +17,8 @@ package ghidra.app.util.bin;
|
|||
|
||||
import java.io.*;
|
||||
|
||||
import ghidra.formats.gfilesystem.FSRL;
|
||||
|
||||
/**
|
||||
* An implementation of {@link ByteProvider} where the underlying bytes are supplied by a static
|
||||
* byte array.
|
||||
|
@ -26,6 +28,7 @@ import java.io.*;
|
|||
public class ByteArrayProvider implements ByteProvider {
|
||||
private byte[] srcBytes;
|
||||
private String name;
|
||||
private FSRL fsrl;
|
||||
|
||||
/**
|
||||
* Constructs a {@link ByteArrayProvider} using the specified byte array
|
||||
|
@ -33,7 +36,18 @@ public class ByteArrayProvider implements ByteProvider {
|
|||
* @param bytes the underlying byte array
|
||||
*/
|
||||
public ByteArrayProvider(byte[] bytes) {
|
||||
this(bytes, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link ByteArrayProvider} using the specified byte array
|
||||
*
|
||||
* @param bytes the underlying byte array
|
||||
* @param fsrl FSRL identity of the file
|
||||
*/
|
||||
public ByteArrayProvider(byte[] bytes, FSRL fsrl) {
|
||||
this.srcBytes = bytes;
|
||||
this.fsrl = fsrl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,6 +66,11 @@ public class ByteArrayProvider implements ByteProvider {
|
|||
// don't do anything for now
|
||||
}
|
||||
|
||||
@Override
|
||||
public FSRL getFSRL() {
|
||||
return fsrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getFile() {
|
||||
return null;
|
||||
|
|
|
@ -17,6 +17,8 @@ package ghidra.app.util.bin;
|
|||
|
||||
import java.io.*;
|
||||
|
||||
import ghidra.formats.gfilesystem.FSRL;
|
||||
|
||||
/**
|
||||
* Creates a {@link ByteProvider} constrained to a sub-section of an existing {@link ByteProvider}.
|
||||
*/
|
||||
|
@ -24,6 +26,7 @@ public class ByteProviderWrapper implements ByteProvider {
|
|||
private ByteProvider provider;
|
||||
private long subOffset;
|
||||
private long subLength;
|
||||
private FSRL fsrl;
|
||||
|
||||
/**
|
||||
* Constructs a {@link ByteProviderWrapper} around the specified {@link ByteProvider}
|
||||
|
@ -34,9 +37,23 @@ public class ByteProviderWrapper implements ByteProvider {
|
|||
* @param subLength the length of the new {@link ByteProviderWrapper}
|
||||
*/
|
||||
public ByteProviderWrapper(ByteProvider provider, long subOffset, long subLength) {
|
||||
this(provider, subOffset, subLength, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link ByteProviderWrapper} around the specified {@link ByteProvider}
|
||||
*
|
||||
* @param provider the {@link ByteProvider} to wrap
|
||||
* @param subOffset the offset in the {@link ByteProvider} of where to start the new
|
||||
* {@link ByteProviderWrapper}
|
||||
* @param subLength the length of the new {@link ByteProviderWrapper}
|
||||
* @param fsrl FSRL identity of the file this ByteProvider represents
|
||||
*/
|
||||
public ByteProviderWrapper(ByteProvider provider, long subOffset, long subLength, FSRL fsrl) {
|
||||
this.provider = provider;
|
||||
this.subOffset = subOffset;
|
||||
this.subLength = subLength;
|
||||
this.fsrl = fsrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -44,6 +61,11 @@ public class ByteProviderWrapper implements ByteProvider {
|
|||
// don't do anything for now
|
||||
}
|
||||
|
||||
@Override
|
||||
public FSRL getFSRL() {
|
||||
return fsrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getFile() {
|
||||
return provider.getFile();
|
||||
|
@ -51,7 +73,7 @@ public class ByteProviderWrapper implements ByteProvider {
|
|||
|
||||
@Override
|
||||
public InputStream getInputStream(long index) throws IOException {
|
||||
return provider.getInputStream(subOffset + index);
|
||||
return new ByteProviderInputStream(this, index, subLength - index);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -59,6 +59,16 @@ public class SingleFileSystemIndexHelper {
|
|||
payloadFile = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified file is the payload file.
|
||||
*
|
||||
* @param file GFile to test
|
||||
* @return boolean true if it is the payload file
|
||||
*/
|
||||
public boolean isPayloadFile(GFile file) {
|
||||
return payloadFile.equals(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this object has been {@link #clear()}'ed.
|
||||
*
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.io.InputStream;
|
|||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.ByteProviderInputStream;
|
||||
import ghidra.app.util.bin.ByteProviderWrapper;
|
||||
import ghidra.app.util.bin.format.coff.CoffException;
|
||||
import ghidra.app.util.bin.format.coff.archive.CoffArchiveHeader;
|
||||
import ghidra.app.util.bin.format.coff.archive.CoffArchiveMemberHeader;
|
||||
|
@ -77,9 +77,15 @@ public class CoffArchiveFileSystem implements GFileSystem {
|
|||
public InputStream getInputStream(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
ByteProvider bp = getByteProvider(file, monitor);
|
||||
return bp != null ? bp.getInputStream(0) : null;
|
||||
}
|
||||
|
||||
public ByteProvider getByteProvider(GFile file, TaskMonitor monitor) {
|
||||
CoffArchiveMemberHeader entry = fsih.getMetadata(file);
|
||||
return (entry != null && entry.isCOFF())
|
||||
? new ByteProviderInputStream(provider, entry.getPayloadOffset(), entry.getSize())
|
||||
? new ByteProviderWrapper(provider, entry.getPayloadOffset(), entry.getSize(),
|
||||
file.getFSRL())
|
||||
: null;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,71 +16,91 @@
|
|||
package ghidra.file.formats.complzss;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.bin.ByteArrayProvider;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.file.formats.lzss.LzssCodec;
|
||||
import ghidra.file.formats.lzss.LzssConstants;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.formats.gfilesystem.annotations.FileSystemInfo;
|
||||
import ghidra.formats.gfilesystem.factory.GFileSystemBaseFactory;
|
||||
import ghidra.util.HashUtilities;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.CryptoException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@FileSystemInfo(type = "lzss", description = "LZSS Compression", factory = GFileSystemBaseFactory.class)
|
||||
public class CompLzssFileSystem extends GFileSystemBase {
|
||||
@FileSystemInfo(type = "lzss", description = "LZSS Compression", factory = CompLzssFileSystemFactory.class)
|
||||
public class CompLzssFileSystem implements GFileSystem {
|
||||
private FSRLRoot fsFSRL;
|
||||
private SingleFileSystemIndexHelper fsIndex;
|
||||
private FileSystemRefManager fsRefManager = new FileSystemRefManager(this);
|
||||
private ByteProvider payloadProvider;
|
||||
|
||||
private static final String NAME = "lzss_decompressed";
|
||||
|
||||
private GFileImpl decompressedFile;
|
||||
private byte[] decompressedBytes;
|
||||
|
||||
public CompLzssFileSystem(String fileSystemName, ByteProvider provider) {
|
||||
super(fileSystemName, provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
decompressedFile = null;
|
||||
decompressedBytes = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InputStream getData(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException, CryptoException {
|
||||
if (file != null && file.equals(decompressedFile)) {
|
||||
return new ByteArrayInputStream(decompressedBytes);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GFile> getListing(GFile directory) throws IOException {
|
||||
return (directory == null || directory.equals(root)) ? Arrays.asList(decompressedFile)
|
||||
: Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(TaskMonitor monitor) throws IOException {
|
||||
byte[] compressionBytes = provider.readBytes(0, 4);
|
||||
byte[] lzssBytes = provider.readBytes(4, 4);
|
||||
|
||||
return Arrays.equals(compressionBytes, LzssConstants.SIGNATURE_COMPRESSION_BYTES) &&
|
||||
Arrays.equals(lzssBytes, LzssConstants.SIGNATURE_LZSS_BYTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(TaskMonitor monitor) throws IOException, CryptoException, CancelledException {
|
||||
public CompLzssFileSystem(FSRLRoot fsrl, ByteProvider provider, TaskMonitor monitor)
|
||||
throws IOException {
|
||||
monitor.setMessage("Decompressing LZSS...");
|
||||
|
||||
byte[] compressedBytes = provider.readBytes(LzssConstants.HEADER_LENGTH,
|
||||
provider.length() - LzssConstants.HEADER_LENGTH);
|
||||
ByteArrayOutputStream decompressedBOS = new ByteArrayOutputStream();
|
||||
LzssCodec.decompress(decompressedBOS, new ByteArrayInputStream(compressedBytes));
|
||||
decompressedBytes = decompressedBOS.toByteArray();
|
||||
decompressedFile =
|
||||
GFileImpl.fromFilename(this, root, NAME, false, decompressedBytes.length, null);
|
||||
debug(decompressedBytes, NAME);
|
||||
byte[] decompressedBytes = decompressedBOS.toByteArray();
|
||||
|
||||
String md5 = HashUtilities.getHash(HashUtilities.MD5_ALGORITHM, decompressedBytes);
|
||||
this.fsIndex = new SingleFileSystemIndexHelper(this, fsFSRL, "lzss_decompressed",
|
||||
decompressedBytes.length, md5);
|
||||
this.payloadProvider =
|
||||
new ByteArrayProvider(decompressedBytes, fsIndex.getPayloadFile().getFSRL());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FSRLRoot getFSRL() {
|
||||
return fsFSRL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return fsFSRL.getContainer().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystemRefManager getRefManager() {
|
||||
return fsRefManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return payloadProvider == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
fsRefManager.onClose();
|
||||
if (payloadProvider != null) {
|
||||
payloadProvider.close();
|
||||
payloadProvider = null;
|
||||
}
|
||||
fsIndex.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
ByteProvider bp = getByteProvider(file, monitor);
|
||||
return bp != null ? bp.getInputStream(0) : null;
|
||||
}
|
||||
|
||||
public ByteProvider getByteProvider(GFile file, TaskMonitor monitor) {
|
||||
return fsIndex.isPayloadFile(file) ? payloadProvider : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GFile> getListing(GFile directory) throws IOException {
|
||||
return fsIndex.getListing(directory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GFile lookup(String path) throws IOException {
|
||||
return fsIndex.lookup(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/* ###
|
||||
* 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.file.formats.complzss;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.file.formats.lzss.LzssCompressionHeader;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.formats.gfilesystem.factory.GFileSystemFactoryFull;
|
||||
import ghidra.formats.gfilesystem.factory.GFileSystemProbeBytesOnly;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class CompLzssFileSystemFactory
|
||||
implements GFileSystemFactoryFull<CompLzssFileSystem>, GFileSystemProbeBytesOnly {
|
||||
|
||||
@Override
|
||||
public CompLzssFileSystem create(FSRL containerFSRL, FSRLRoot targetFSRL,
|
||||
ByteProvider byteProvider, File containerFile, FileSystemService fsService,
|
||||
TaskMonitor monitor) throws IOException, CancelledException {
|
||||
|
||||
CompLzssFileSystem fs = new CompLzssFileSystem(targetFSRL, byteProvider, monitor);
|
||||
return fs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytesRequired() {
|
||||
return LzssCompressionHeader.PROBE_BYTES_NEEDED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean probeStartBytes(FSRL containerFSRL, byte[] startBytes) {
|
||||
return LzssCompressionHeader.probe(startBytes);
|
||||
}
|
||||
}
|
|
@ -16,86 +16,107 @@
|
|||
package ghidra.file.formats.cpio;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.compress.archivers.cpio.CpioArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream;
|
||||
|
||||
import ghidra.app.util.bin.ByteArrayProvider;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.formats.gfilesystem.FSUtilities.StreamCopyResult;
|
||||
import ghidra.formats.gfilesystem.annotations.FileSystemInfo;
|
||||
import ghidra.formats.gfilesystem.factory.GFileSystemBaseFactory;
|
||||
import ghidra.util.NumericUtilities;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.CryptoException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
@FileSystemInfo(type = "cpio", description = "CPIO", factory = GFileSystemBaseFactory.class)
|
||||
public class CpioFileSystem extends GFileSystemBase {
|
||||
@FileSystemInfo(type = "cpio", description = "CPIO", factory = CpioFileSystemFactory.class)
|
||||
public class CpioFileSystem implements GFileSystem {
|
||||
private FSRLRoot fsFSRL;
|
||||
private FileSystemIndexHelper<CpioArchiveEntry> fsIndex;
|
||||
private FileSystemRefManager fsRefManager = new FileSystemRefManager(this);
|
||||
private ByteProvider provider;
|
||||
|
||||
private Map<GFile, CpioArchiveEntry> map = new HashMap<>();
|
||||
|
||||
public CpioFileSystem(String fileSystemName, ByteProvider provider) {
|
||||
super(fileSystemName, provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(TaskMonitor monitor) throws IOException {
|
||||
byte[] signature = provider.readBytes(0, 0x10);
|
||||
return CpioArchiveInputStream.matches(signature, 0x10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(TaskMonitor monitor) throws IOException, CryptoException, CancelledException {
|
||||
public CpioFileSystem(FSRLRoot fsFSRL, ByteProvider provider, TaskMonitor monitor)
|
||||
throws IOException {
|
||||
monitor.setMessage("Opening CPIO...");
|
||||
this.fsFSRL = fsFSRL;
|
||||
this.provider = provider;
|
||||
this.fsIndex = new FileSystemIndexHelper<>(this, fsFSRL);
|
||||
|
||||
try (CpioArchiveInputStream cpioInputStream =
|
||||
new CpioArchiveInputStream(provider.getInputStream(0))) {
|
||||
CpioArchiveEntry entry;
|
||||
int fileNum = 0;
|
||||
while ((entry = cpioInputStream.getNextCPIOEntry()) != null) {
|
||||
skipEntryContents(cpioInputStream, monitor);
|
||||
storeEntry(entry, monitor);
|
||||
FileUtilities.copyStreamToStream(cpioInputStream, OutputStream.nullOutputStream(),
|
||||
monitor);
|
||||
|
||||
monitor.setMessage(entry.getName());
|
||||
fsIndex.storeFile(entry.getName(), fileNum++, entry.isDirectory(),
|
||||
entry.getSize(), entry);
|
||||
}
|
||||
}
|
||||
catch (EOFException e) {
|
||||
// silently ignore EOFExceptions
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
FSUtilities.displayException(this, null, "Error While Opening CPIO", e.getMessage(), e);
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
map.clear();
|
||||
fsRefManager.onClose();
|
||||
fsIndex.clear();
|
||||
if (provider != null) {
|
||||
provider.close();
|
||||
provider = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FSRLRoot getFSRL() {
|
||||
return fsFSRL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return fsFSRL.getContainer().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return provider == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystemRefManager getRefManager() {
|
||||
return fsRefManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GFile> getListing(GFile directory) throws IOException {
|
||||
if (directory == null || directory.equals(root)) {
|
||||
List<GFile> roots = new ArrayList<>();
|
||||
for (GFile file : map.keySet()) {
|
||||
if (file.getParentFile() == root || file.getParentFile().equals(root)) {
|
||||
roots.add(file);
|
||||
return fsIndex.getListing(directory);
|
||||
}
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
List<GFile> tmp = new ArrayList<>();
|
||||
for (GFile file : map.keySet()) {
|
||||
if (file.getParentFile() == null) {
|
||||
continue;
|
||||
}
|
||||
if (file.getParentFile().equals(directory)) {
|
||||
tmp.add(file);
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
|
||||
@Override
|
||||
public GFile lookup(String path) throws IOException {
|
||||
return fsIndex.lookup(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfo(GFile file, TaskMonitor monitor) {
|
||||
CpioArchiveEntry entry = map.get(file);
|
||||
CpioArchiveEntry entry = fsIndex.getMetadata(file);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
try {
|
||||
buffer.append("Name: " + entry.getName() + "\n");
|
||||
|
@ -129,84 +150,46 @@ public class CpioFileSystem extends GFileSystemBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected InputStream getData(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException, CryptoException {
|
||||
CpioArchiveEntry fileEntry = map.get(file);
|
||||
if (!fileEntry.isRegularFile()) {
|
||||
public InputStream getInputStream(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
ByteProvider bp = getByteProvider(file, monitor);
|
||||
return bp != null ? bp.getInputStream(0) : null;
|
||||
}
|
||||
|
||||
public ByteProvider getByteProvider(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
CpioArchiveEntry targetEntry = fsIndex.getMetadata(file);
|
||||
if (targetEntry == null) {
|
||||
return null;
|
||||
}
|
||||
if (!targetEntry.isRegularFile()) {
|
||||
throw new IOException("CPIO entry " + file.getName() + " is not a regular file.");
|
||||
}
|
||||
try (CpioArchiveInputStream cpioInputStream =
|
||||
new CpioArchiveInputStream(provider.getInputStream(0));) {
|
||||
new CpioArchiveInputStream(provider.getInputStream(0))) {
|
||||
|
||||
CpioArchiveEntry entry;
|
||||
while ((entry = cpioInputStream.getNextCPIOEntry()) != null) {
|
||||
if (!entry.equals(fileEntry)) {
|
||||
skipEntryContents(cpioInputStream, monitor);
|
||||
}
|
||||
else {
|
||||
byte[] entryBytes = readEntryContents(cpioInputStream, monitor);
|
||||
return new ByteArrayInputStream(entryBytes);
|
||||
CpioArchiveEntry currentEntry;
|
||||
while ((currentEntry = cpioInputStream.getNextCPIOEntry()) != null) {
|
||||
if (currentEntry.equals(targetEntry)) {
|
||||
return getByteProviderForEntry(cpioInputStream, file.getFSRL(), monitor);
|
||||
}
|
||||
FileUtilities.copyStreamToStream(cpioInputStream, OutputStream.nullOutputStream(),
|
||||
monitor);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
//unknown MODES..
|
||||
throw new IOException(e);
|
||||
}
|
||||
return null;
|
||||
throw new IOException("Unable to seek to entry: " + file.getName());
|
||||
}
|
||||
|
||||
private void storeEntry(CpioArchiveEntry entry, TaskMonitor monitor) {
|
||||
monitor.setMessage(entry.getName());
|
||||
GFileImpl file = GFileImpl.fromPathString(this, root, entry.getName(), null,
|
||||
entry.isDirectory(), entry.getSize());
|
||||
storeFile(file, entry, monitor);
|
||||
}
|
||||
|
||||
private void storeFile(GFile file, CpioArchiveEntry entry, TaskMonitor monitor) {
|
||||
if (monitor.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
if (file.equals(root)) {
|
||||
return;
|
||||
}
|
||||
if (!map.containsKey(file) || map.get(file) == null) {
|
||||
map.put(file, entry);
|
||||
}
|
||||
GFile parentFile = file.getParentFile();
|
||||
storeFile(parentFile, null, monitor);
|
||||
}
|
||||
|
||||
private byte[] readEntryContents(CpioArchiveInputStream cpioInputStream, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
private ByteProvider getByteProviderForEntry(CpioArchiveInputStream cpioInputStream, FSRL fsrl,
|
||||
TaskMonitor monitor) throws CancelledException, IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[64 * 1024];
|
||||
while (true) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
int bytesRead = cpioInputStream.read(buffer);
|
||||
if (bytesRead <= 0) {
|
||||
break;
|
||||
}
|
||||
out.write(buffer, 0, bytesRead);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
private void skipEntryContents(CpioArchiveInputStream cpioInputStream, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
byte[] buffer = new byte[64 * 1024];
|
||||
while (true) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
int bytesRead = cpioInputStream.read(buffer);
|
||||
if (bytesRead <= 0) {
|
||||
break;
|
||||
}
|
||||
StreamCopyResult copyResult = FSUtilities.streamCopy(cpioInputStream, out, monitor);
|
||||
if (fsrl.getMD5() == null) {
|
||||
fsrl = fsrl.withMD5(NumericUtilities.convertBytesToString(copyResult.md5));
|
||||
}
|
||||
return new ByteArrayProvider(out.toByteArray(), fsrl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/* ###
|
||||
* 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.file.formats.cpio;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream;
|
||||
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.formats.gfilesystem.*;
|
||||
import ghidra.formats.gfilesystem.factory.GFileSystemFactoryFull;
|
||||
import ghidra.formats.gfilesystem.factory.GFileSystemProbeBytesOnly;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class CpioFileSystemFactory
|
||||
implements GFileSystemFactoryFull<CpioFileSystem>, GFileSystemProbeBytesOnly {
|
||||
|
||||
@Override
|
||||
public CpioFileSystem create(FSRL containerFSRL, FSRLRoot targetFSRL,
|
||||
ByteProvider byteProvider, File containerFile, FileSystemService fsService,
|
||||
TaskMonitor monitor) throws IOException, CancelledException {
|
||||
|
||||
CpioFileSystem fs = new CpioFileSystem(targetFSRL, byteProvider, monitor);
|
||||
return fs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytesRequired() {
|
||||
return 6; // CpioArchiveInputStream doesn't have a value we can use, so we hard code
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean probeStartBytes(FSRL containerFSRL, byte[] startBytes) {
|
||||
return CpioArchiveInputStream.matches(startBytes, startBytes.length);
|
||||
}
|
||||
}
|
|
@ -46,7 +46,6 @@ public class GZipFileSystem implements GFileSystem {
|
|||
private final SingleFileSystemIndexHelper fsIndex;
|
||||
private final FileSystemService fsService;
|
||||
|
||||
private GFile payload;
|
||||
private String origFilename;
|
||||
private String payloadKey;
|
||||
private String origComment;
|
||||
|
@ -64,7 +63,6 @@ public class GZipFileSystem implements GFileSystem {
|
|||
FileCacheEntry fce = getPayloadFileCacheEntry(monitor);
|
||||
this.fsIndex =
|
||||
new SingleFileSystemIndexHelper(this, fsFSRL, origFilename, fce.file.length(), fce.md5);
|
||||
this.payload = fsIndex.getPayloadFile();
|
||||
}
|
||||
|
||||
private void readGzipMetadata(File containerFile, TaskMonitor monitor) throws IOException {
|
||||
|
@ -101,7 +99,7 @@ public class GZipFileSystem implements GFileSystem {
|
|||
}
|
||||
|
||||
public GFile getPayloadFile() {
|
||||
return payload;
|
||||
return fsIndex.getPayloadFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,7 +116,6 @@ public class GZipFileSystem implements GFileSystem {
|
|||
public void close() throws IOException {
|
||||
refManager.onClose();
|
||||
fsIndex.clear();
|
||||
payload = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -134,7 +131,7 @@ public class GZipFileSystem implements GFileSystem {
|
|||
@Override
|
||||
public InputStream getInputStream(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
if (payload.equals(file)) {
|
||||
if (fsIndex.isPayloadFile(file)) {
|
||||
FileCacheEntry fce = getPayloadFileCacheEntry(monitor);
|
||||
return new FileInputStream(fce.file);
|
||||
}
|
||||
|
@ -148,13 +145,14 @@ public class GZipFileSystem implements GFileSystem {
|
|||
|
||||
@Override
|
||||
public String getInfo(GFile file, TaskMonitor monitor) {
|
||||
if (payload.equals(file)) {
|
||||
if (fsIndex.isPayloadFile(file)) {
|
||||
return FSUtilities.infoMapToString(getInfoMap());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<String, String> getInfoMap() {
|
||||
GFile payload = fsIndex.getPayloadFile();
|
||||
Map<String, String> info = new LinkedHashMap<>();
|
||||
info.put("Name", payload.getName());
|
||||
info.put("Size", Long.toString(payload.getLength()));
|
||||
|
|
|
@ -15,14 +15,15 @@
|
|||
*/
|
||||
package ghidra.file.formats.iso9660;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.IOException;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.formats.gfilesystem.FSRL;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class ISO9660Directory implements StructConverter {
|
||||
|
||||
private int directoryRecordLength;
|
||||
|
@ -175,21 +176,11 @@ public class ISO9660Directory implements StructConverter {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bytes of the file which this directory points to
|
||||
* @param provider The ByteProvider
|
||||
* @param logicalBlockSize
|
||||
* @return An InputStream of the data bytes
|
||||
* @throws IOException
|
||||
*/
|
||||
public InputStream getDataBytes(ByteProvider provider, long logicalBlockSize)
|
||||
throws IOException {
|
||||
ByteProvider getByteProvider(ByteProvider provider, long logicalBlockSize, FSRL fsrl) {
|
||||
|
||||
if (!(this.isDirectoryFlagSet())) {
|
||||
if (!this.isDirectoryFlagSet()) {
|
||||
long index = locationOfExtentLE * logicalBlockSize;
|
||||
byte[] dataBytes = provider.readBytes(index, dataLengthLE);
|
||||
InputStream inputStream = new ByteArrayInputStream(dataBytes);
|
||||
return inputStream;
|
||||
return new ByteProviderWrapper(provider, index, dataLengthLE, fsrl);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -15,10 +15,9 @@
|
|||
*/
|
||||
package ghidra.file.formats.iso9660;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
|
@ -148,10 +147,14 @@ public class ISO9660FileSystem extends GFileSystemBase {
|
|||
protected InputStream getData(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException, CryptoException {
|
||||
|
||||
ISO9660Directory dir = fileToDirectoryMap.get(file);
|
||||
InputStream inputStream = dir.getDataBytes(provider, logicalBlockSize);
|
||||
ByteProvider bp = getByteProvider(file, monitor);
|
||||
return bp != null ? bp.getInputStream(0) : null;
|
||||
}
|
||||
|
||||
return inputStream;
|
||||
public ByteProvider getByteProvider(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
ISO9660Directory dir = fileToDirectoryMap.get(file);
|
||||
return dir.getByteProvider(provider, logicalBlockSize, file.getFSRL());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -126,7 +126,7 @@ public class JavaClassDecompilerFileSystem implements GFileSystem {
|
|||
@Override
|
||||
public InputStream getInputStream(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
if (fsIndexHelper.getPayloadFile().equals(file)) {
|
||||
if (fsIndexHelper.isPayloadFile(file)) {
|
||||
FileCacheEntry fce = getDecompiledJavaSrcFileEntry(monitor);
|
||||
return new FileInputStream(fce.file);
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ public class JavaClassDecompilerFileSystem implements GFileSystem {
|
|||
|
||||
@Override
|
||||
public String getInfo(GFile file, TaskMonitor monitor) {
|
||||
if (fsIndexHelper.getPayloadFile().equals(file)) {
|
||||
if (fsIndexHelper.isPayloadFile(file)) {
|
||||
Map<String, String> info = new HashMap<>();
|
||||
info.put("Class name", className);
|
||||
return FSUtilities.infoMapToString(info);
|
||||
|
|
|
@ -15,20 +15,46 @@
|
|||
*/
|
||||
package ghidra.file.formats.lzss;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class LzssCompressionHeader implements StructConverter {
|
||||
|
||||
public static final int PROBE_BYTES_NEEDED = 8; // sizeof(signature) + sizeof(compressionType)
|
||||
|
||||
/**
|
||||
* Returns true if the bytes have the magic signature of a LzssCompressionHeader.
|
||||
*
|
||||
* @param startBytes byte array
|
||||
* @return boolean true if the signature of a LzssCompressionHeader appears at the beginning
|
||||
* the byte array
|
||||
*/
|
||||
public static boolean probe(byte[] startBytes) {
|
||||
try {
|
||||
if (startBytes.length < PROBE_BYTES_NEEDED) {
|
||||
return false;
|
||||
}
|
||||
BinaryReader reader = new BinaryReader(new ByteArrayProvider(startBytes), false);
|
||||
|
||||
int signature = reader.readNextInt();
|
||||
int compressionType = reader.readNextInt();
|
||||
return signature == LzssConstants.SIGNATURE_LZSS &&
|
||||
compressionType == LzssConstants.SIGNATURE_COMPRESSION;
|
||||
}
|
||||
catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private int signature;
|
||||
private int compressionType;
|
||||
private int checksum;
|
||||
private int decompressedLength;
|
||||
private int compressedLength;
|
||||
private byte [] padding;
|
||||
private byte[] padding;
|
||||
|
||||
public LzssCompressionHeader(ByteProvider provider) throws IOException {
|
||||
BinaryReader reader = new BinaryReader(provider, false);
|
||||
|
@ -60,6 +86,7 @@ public class LzssCompressionHeader implements StructConverter {
|
|||
return padding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
return StructConverterUtil.toDataType(this);
|
||||
}
|
||||
|
|
|
@ -98,9 +98,15 @@ public class OmfArchiveFileSystem implements GFileSystem {
|
|||
public InputStream getInputStream(GFile file, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
ByteProvider bp = getByteProvider(file, monitor);
|
||||
return bp != null ? bp.getInputStream(0) : null;
|
||||
}
|
||||
|
||||
public ByteProvider getByteProvider(GFile file, TaskMonitor monitor) {
|
||||
OmfLibraryRecord.MemberHeader member = fsih.getMetadata(file);
|
||||
return (member != null)
|
||||
? new ByteProviderInputStream(provider, member.payloadOffset, member.size)
|
||||
? new ByteProviderWrapper(provider, member.payloadOffset, member.size,
|
||||
file.getFSRL())
|
||||
: null;
|
||||
}
|
||||
|
||||
|
|
|
@ -170,6 +170,21 @@ public class HashUtilities {
|
|||
return NumericUtilities.convertBytesToString(messageDigest.digest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate combined message digest hash for the bytes in the specified array.
|
||||
*
|
||||
* @param algorithm message digest algorithm
|
||||
* @param values array of bytes to hash
|
||||
* @return message digest hash
|
||||
* @throws IllegalArgumentException if specified algorithm is not supported
|
||||
* @see MessageDigest for supported hash algorithms
|
||||
*/
|
||||
public static String getHash(String algorithm, byte[] values) {
|
||||
MessageDigest messageDigest = getMessageDigest(algorithm);
|
||||
messageDigest.update(values);
|
||||
return NumericUtilities.convertBytesToString(messageDigest.digest());
|
||||
}
|
||||
|
||||
private static MessageDigest getMessageDigest(String algorithm) {
|
||||
try {
|
||||
return MessageDigest.getInstance(algorithm);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue