Merge remote-tracking branch 'origin/GP-2553_dev747368_fix_memorybyteprovider_length_take2--SQUASHED'

This commit is contained in:
Ryan Kurtz 2022-09-27 00:37:58 -04:00
commit d959fe5cb7
58 changed files with 775 additions and 2295 deletions

View file

@ -15,9 +15,10 @@
*/
package ghidra.app.cmd.formats;
import java.io.IOException;
import java.util.List;
import java.io.IOException;
import ghidra.app.plugin.core.analysis.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.util.bin.ByteProvider;
@ -49,8 +50,8 @@ public class AppleSingleDoubleBinaryAnalysisCommand extends FlatProgramAPI
public boolean analysisWorkerCallback(Program program, Object workerContext,
TaskMonitor monitor) throws CancelledException, Exception {
try {
ByteProvider provider = new MemoryByteProvider(currentProgram.getMemory(),
currentProgram.getAddressFactory().getDefaultAddressSpace());
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
AppleSingleDouble header = new AppleSingleDouble(provider);
Address address = toAddr(0);

View file

@ -44,8 +44,8 @@ public class CoffArchiveBinaryAnalysisCommand extends FlatProgramAPI
public boolean analysisWorkerCallback(Program program, Object workerContext,
TaskMonitor monitor) throws Exception, CancelledException {
ByteProvider provider = new MemoryByteProvider(currentProgram.getMemory(),
currentProgram.getAddressFactory().getDefaultAddressSpace());
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
if (!CoffArchiveHeader.isMatch(provider)) {
return false;

View file

@ -66,9 +66,8 @@ public class CoffBinaryAnalysisCommand extends FlatProgramAPI
public boolean analysisWorkerCallback(Program program, Object workerContext,
TaskMonitor monitor) throws Exception, CancelledException {
ByteProvider provider = new MemoryByteProvider(currentProgram.getMemory(),
currentProgram.getAddressFactory().getDefaultAddressSpace());
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
CoffFileHeader header = new CoffFileHeader(provider);
if (!CoffMachineType.isMachineTypeDefined(header.getMagic())) {

View file

@ -77,8 +77,8 @@ public class ElfBinaryAnalysisCommand extends FlatProgramAPI
Listing listing = currentProgram.getListing();
SymbolTable symbolTable = currentProgram.getSymbolTable();
ByteProvider provider = new MemoryByteProvider(currentProgram.getMemory(),
currentProgram.getAddressFactory().getDefaultAddressSpace());
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
try {
ElfHeader elf = new ElfHeader(provider, msg -> messages.appendMsg(msg));
elf.parse();

View file

@ -89,8 +89,8 @@ public class MachoBinaryAnalysisCommand extends FlatProgramAPI
BookmarkManager bookmarkManager = program.getBookmarkManager();
ByteProvider provider = new MemoryByteProvider(program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace());
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
try {
MachHeader header =

View file

@ -15,6 +15,10 @@
*/
package ghidra.app.cmd.formats;
import java.util.List;
import java.io.IOException;
import ghidra.app.cmd.data.CreateStringCmd;
import ghidra.app.plugin.core.analysis.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
@ -32,9 +36,6 @@ import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
import java.io.IOException;
import java.util.List;
public class PefBinaryAnalysisCommand extends FlatProgramAPI implements BinaryAnalysisCommand,
AnalysisWorker {
private MessageLog messages = new MessageLog();
@ -47,8 +48,7 @@ public class PefBinaryAnalysisCommand extends FlatProgramAPI implements BinaryAn
public boolean canApply(Program program) {
try {
ByteProvider provider =
new MemoryByteProvider(program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace());
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
new ContainerHeader(provider);
return true;
}
@ -61,8 +61,7 @@ public class PefBinaryAnalysisCommand extends FlatProgramAPI implements BinaryAn
public boolean analysisWorkerCallback(Program program, Object workerContext, TaskMonitor monitor)
throws Exception, CancelledException {
ByteProvider provider =
new MemoryByteProvider(currentProgram.getMemory(),
program.getAddressFactory().getDefaultAddressSpace());
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
try {
ContainerHeader header = new ContainerHeader(provider);
header.parse();

View file

@ -15,9 +15,10 @@
*/
package ghidra.app.cmd.formats;
import java.io.IOException;
import java.util.List;
import java.io.IOException;
import ghidra.app.plugin.core.analysis.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.util.bin.*;
@ -32,7 +33,6 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
@ -48,11 +48,8 @@ public class PortableExecutableBinaryAnalysisCommand extends FlatProgramAPI
@Override
public boolean canApply(Program program) {
try {
Memory memory = program.getMemory();
ByteProvider provider = new MemoryByteProvider(memory,
program.getAddressFactory().getDefaultAddressSpace());
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
DOSHeader dosHeader = new DOSHeader(reader);
@ -75,8 +72,8 @@ public class PortableExecutableBinaryAnalysisCommand extends FlatProgramAPI
public boolean analysisWorkerCallback(Program program, Object workerContext,
TaskMonitor monitor) throws Exception, CancelledException {
ByteProvider provider = new MemoryByteProvider(currentProgram.getMemory(),
program.getAddressFactory().getDefaultAddressSpace());
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
PortableExecutable pe = new PortableExecutable(provider, SectionLayout.FILE);

View file

@ -15,9 +15,10 @@
*/
package ghidra.app.plugin.core.analysis;
import java.util.List;
import java.io.File;
import java.io.IOException;
import java.util.List;
import ghidra.app.services.*;
import ghidra.app.util.bin.*;
@ -46,6 +47,7 @@ public class DwarfLineNumberAnalyzer extends AbstractAnalyzer {
setSupportsOneTimeAnalysis();
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
AddressSpace space = program.getAddressFactory().getDefaultAddressSpace();
@ -59,7 +61,7 @@ public class DwarfLineNumberAnalyzer extends AbstractAnalyzer {
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
while (!monitor.isCancelled() && reader.getPointerIndex() < provider.length()) {
while (!monitor.isCancelled() && reader.hasNext()) {
long startIndex = reader.getPointerIndex();
StatementProgramPrologue prologue = new StatementProgramPrologue(reader);
@ -134,10 +136,9 @@ public class DwarfLineNumberAnalyzer extends AbstractAnalyzer {
else if (ElfLoader.ELF_NAME.equals(program.getExecutableFormat())) {
// We now load the .debug section as an overlay block, no need for the
// original file
MemoryBlock block = null;
block = program.getMemory().getBlock(sectionNames.SECTION_NAME_LINE());
MemoryBlock block = program.getMemory().getBlock(sectionNames.SECTION_NAME_LINE());
if (block != null) {
return new MemoryByteProvider(program.getMemory(), block.getStart());
return MemoryByteProvider.createMemoryBlockByteProvider(program.getMemory(), block);
}
// TODO: this will not handle the case where the .debug section is
// in a separate file. Can the file in a separate location?
@ -147,6 +148,7 @@ public class DwarfLineNumberAnalyzer extends AbstractAnalyzer {
program.getExecutableFormat());
}
@Override
public boolean canAnalyze(Program program) {
return isElfOrMacho(program);

View file

@ -15,6 +15,11 @@
*/
package ghidra.app.plugin.core.analysis;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import ghidra.app.services.*;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.MemoryByteProvider;
@ -28,10 +33,6 @@ import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ObjectiveC1_ClassAnalyzer extends AbstractAnalyzer {
private static final String DESCRIPTION =
"An analyzer for extracting Objective-C class structure information.";
@ -46,13 +47,12 @@ public class ObjectiveC1_ClassAnalyzer extends AbstractAnalyzer {
setDefaultEnablement(true);
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
MemoryByteProvider provider =
new MemoryByteProvider(program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace());
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
ObjectiveC1_State state =
@ -94,6 +94,7 @@ public class ObjectiveC1_ClassAnalyzer extends AbstractAnalyzer {
}
}
@Override
public boolean canAnalyze(Program program) {
return ObjectiveC1_Constants.isObjectiveC(program);
}

View file

@ -15,9 +15,10 @@
*/
package ghidra.app.plugin.core.analysis;
import java.io.IOException;
import java.util.*;
import java.io.IOException;
import ghidra.app.services.*;
import ghidra.app.util.bin.*;
import ghidra.app.util.bin.format.macho.dyld.LibObjcOptimization;
@ -67,8 +68,8 @@ public class ObjectiveC2_ClassAnalyzer extends AbstractAnalyzer {
ObjectiveC2_State state =
new ObjectiveC2_State(program, monitor, ObjectiveC2_Constants.CATEGORY_PATH);
try (ByteProvider provider = new MemoryByteProvider(program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace())) {
try (ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false)) {
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
// Create a map of Objective-C specific memory blocks. If this is a dyld_shared_cache

View file

@ -28,6 +28,12 @@ import ghidra.util.*;
*
*/
public class BinaryReader {
// jvm's will typically refuse to allocate arrays that are exactly Integer.MAX_VALUE.
// This is a conservative stab at a max array element count since we don't have a requirement
// to reach exactly 2g elements
private static final int MAX_SANE_BUFFER = Integer.MAX_VALUE - 1024;
/**
* The size of a BYTE in Java.
*/
@ -66,7 +72,7 @@ public class BinaryReader {
public BinaryReader(ByteProvider provider, boolean isLittleEndian) {
this(provider, DataConverter.getInstance(!isLittleEndian), 0);
}
/**
* Creates a BinaryReader instance.
*
@ -147,6 +153,7 @@ public class BinaryReader {
/**
* Returns the length of the underlying file.
*
* @return returns the length of the underlying file
* @exception IOException if an I/O error occurs
*/
@ -155,18 +162,19 @@ public class BinaryReader {
}
/**
* Returns true if the specified index into
* the underlying byte provider is valid.
* @param index the index in the byte provider
* Returns true if the specified unsigned int32 index into the underlying byte provider is
* valid.
*
* @param index an integer that is treated as an unsigned int32 index into the byte provider
* @return returns true if the specified index is valid
*/
public boolean isValidIndex(int index) {
return provider.isValidIndex(index & Conv.INT_MASK);
return provider.isValidIndex(Integer.toUnsignedLong(index));
}
/**
* Returns true if the specified index into
* the underlying byte provider is valid.
* Returns true if the specified index into the underlying byte provider is valid.
*
* @param index the index in the byte provider
* @return returns true if the specified index is valid
*/
@ -175,19 +183,75 @@ public class BinaryReader {
}
/**
* Aligns the current index on the specified alignment value.
* For example, if current index was 123 and align value was
* 16, then current index would become 128.
* Returns true if the specified range is valid and does not wrap around the end of the
* index space.
*
* @param startIndex the starting index to check, treated as an unsigned int64
* @param count the number of bytes to check
* @return boolean true if all bytes between startIndex to startIndex+count (exclusive) are
* valid (according to the underlying byte provider)
*/
public boolean isValidRange(long startIndex, int count) {
if (count < 0) {
return false;
}
if (count > 1) {
// check the end of the range first to fail fast
long endIndex = startIndex + (count - 1);
if (Long.compareUnsigned(endIndex, startIndex) < 0) {
// the requested range [startIndex..startIndex+count] wraps around the int64 to 0, so fail
return false;
}
if (!provider.isValidIndex(endIndex)) {
return false;
}
count--; // don't check the last element twice
}
for (int i = 0; i < count; i++) {
if (!provider.isValidIndex(startIndex + i)) {
return false;
}
}
return true;
}
/**
* Returns true if this stream has data that could be read at the current position.
*
* @return true if there are more bytes that could be read at the
* {@link #getPointerIndex() current index}.
*/
public boolean hasNext() {
return provider.isValidIndex(currentIndex);
}
/**
* Returns true if this stream has data that could be read at the current position.
*
* @param count number of bytes to verify
* @return true if there are at least count more bytes that could be read at the
* {@link #getPointerIndex() current index}.
*/
public boolean hasNext(int count) {
return isValidRange(currentIndex, count);
}
/**
* Advances the current index so that it aligns to the specified value (if not already
* aligned).
* <p>
* For example, if current index was 123 and align value was 16, then current index would
* be advanced to 128.
*
* @param alignValue
* @return the number of bytes required to align
* @return the number of bytes required to align (0..alignValue-1)
*/
public int align(int alignValue) {
long align = currentIndex % alignValue;
if (align == 0) {
return 0;
}
currentIndex = currentIndex + (alignValue - align);
return (int) (alignValue - align);
long prevIndex = currentIndex;
currentIndex = NumericUtilities.getUnsignedAlignedValue(currentIndex, alignValue);
return (int) (currentIndex - prevIndex);
}
////////////////////////////////////////////////////////////////////
@ -279,7 +343,7 @@ public class BinaryReader {
* @exception IOException if an I/O error occurs
*/
public int readNextUnsignedByte() throws IOException {
return readNextByte() & NumberUtil.UNSIGNED_BYTE_MASK;
return Byte.toUnsignedInt(readNextByte());
}
/**
@ -301,7 +365,7 @@ public class BinaryReader {
* @exception IOException if an I/O error occurs
*/
public int readNextUnsignedShort() throws IOException {
return readNextShort() & NumberUtil.UNSIGNED_SHORT_MASK;
return Short.toUnsignedInt(readNextShort());
}
/**
@ -323,7 +387,7 @@ public class BinaryReader {
* @exception IOException if an I/O error occurs
*/
public long readNextUnsignedInt() throws IOException {
return readNextInt() & NumberUtil.UNSIGNED_INT_MASK;
return Integer.toUnsignedLong(readNextInt());
}
/**
@ -463,7 +527,6 @@ public class BinaryReader {
return result;
}
/**
* Reads a byte array of <code>nElements</code>
* starting at the current index and then increments the current
@ -520,20 +583,33 @@ public class BinaryReader {
// String stuff
//--------------------------------------------------------------------------------------------
private byte[] readUntilNullTerm(long index, int charLen) throws IOException {
long maxPos = provider.length() - charLen;
if (index > maxPos) {
throw new EOFException(String.format("Attempted to read string at 0x%x", index));
}
long curPos = index;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (; curPos <= maxPos; curPos += charLen) {
byte[] bytes = readByteArray(curPos, charLen);
if (isNullTerm(bytes, 0, charLen)) {
return baos.toByteArray();
long curPos = index;
for (; Long.compareUnsigned(curPos, index) >= 0; curPos += charLen) {
// loop while we haven't wrapped the index value around to 0
if ((long) baos.size() + charLen >= MAX_SANE_BUFFER) {
// gracefully handle hitting the limit of the ByteArrayOutputStream before it fails
throw new EOFException("Run-on unterminated string at 0x%s..0x%s".formatted(
Long.toUnsignedString(index, 16), Long.toUnsignedString(curPos, 16)));
}
try {
byte[] bytes = readByteArray(curPos, charLen);
if (isNullTerm(bytes, 0, charLen)) {
return baos.toByteArray();
}
baos.write(bytes);
}
catch (IOException e) {
if (baos.size() == 0) {
// failed trying to read the first byte
throw new EOFException("Attempted to read string at 0x%s"
.formatted(Long.toUnsignedString(index, 16)));
}
break; // fall thru to throw new EOF(unterminate string)
}
baos.write(bytes);
}
throw new EOFException(String.format("Unterminated string at 0x%x..0x%x", index, curPos));
throw new EOFException("Unterminated string at 0x%s..0x%s"
.formatted(Long.toUnsignedString(index, 16), Long.toUnsignedString(curPos, 16)));
}
private boolean isNullTerm(byte[] bytes, int offset, int charLen) {
@ -711,7 +787,7 @@ public class BinaryReader {
* @exception IOException if an I/O error occurs
*/
public int readUnsignedByte(long index) throws IOException {
return readByte(index) & NumberUtil.UNSIGNED_BYTE_MASK;
return Byte.toUnsignedInt(readByte(index));
}
/**
@ -732,7 +808,7 @@ public class BinaryReader {
* @exception IOException if an I/O error occurs
*/
public int readUnsignedShort(long index) throws IOException {
return readShort(index) & NumberUtil.UNSIGNED_SHORT_MASK;
return Short.toUnsignedInt(readShort(index));
}
/**
@ -753,7 +829,7 @@ public class BinaryReader {
* @exception IOException if an I/O error occurs
*/
public long readUnsignedInt(long index) throws IOException {
return readInt(index) & NumberUtil.UNSIGNED_INT_MASK;
return Integer.toUnsignedLong(readInt(index));
}
/**

View file

@ -74,6 +74,20 @@ public interface ByteProvider extends Closeable {
*/
public long length() throws IOException;
/**
* Returns true if this ByteProvider does not contain any bytes.
*
* @return boolean true if this provider is empty, false if contains bytes
*/
default public boolean isEmpty() {
try {
return length() == 0;
}
catch (IOException e) {
return true;
}
}
/**
* Returns true if the specified index is valid.
*
@ -127,4 +141,5 @@ public interface ByteProvider extends Closeable {
}
return new ByteProviderInputStream(this, index);
}
}

View file

@ -81,6 +81,11 @@ public class EmptyByteProvider implements ByteProvider {
return 0;
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public boolean isValidIndex(long index) {
return false;

View file

@ -18,11 +18,37 @@ package ghidra.app.util.bin;
import java.io.*;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock;
/**
* A {@link ByteProvider} implementation based on {@link Memory}.
* <p>
* The bytes returned by this provider are indexed relative to the {@code baseAddress}
* supplied to the constructor, and are limited to {@link MemoryBlock memory blocks} of the
* same address space.
* <p>
* <b>Warnings:</b>
* <p>
* Using this ByteProvider with memory block/address spaces that are not simple "ram" initialized
* memory blocks is fraught with peril.
* <p>
* Addresses and address spaces can use all 64 bits of a {@code long} as an offset, which
* causes a problem when trying to express the correct {@link #length()} of this ByteProvider as
* a long. (this is why address ranges deal with inclusive end values instead of exclusive).
* <ul>
* <li>The return value of {@link #length()} is constrained to a max of Long.MAX_VALUE</li>
* <li>{@link #isValidIndex(long)} treats its argument as an unsigned int64, and works
* for the entire address space range.</li>
* </ul>
* <p>
* Not all byte provider index locations between 0 and {@link #length()} will be valid
* (because gaps between memory blocks), and may generate exceptions when those locations are read.
* <ul>
* <li>To avoid this situation, the caller will need to use information from the program's Memory
* manager to align reads to valid locations.</li>
* </ul>
*/
public class MemoryByteProvider implements ByteProvider {
@ -33,54 +59,149 @@ public class MemoryByteProvider implements ByteProvider {
* @param block {@link MemoryBlock} to read from
* @return new {@link ByteProvider} that contains the bytes of the specified MemoryBlock
*/
public static ByteProvider createMemoryBlockByteProvider(Memory memory, MemoryBlock block) {
long blockLen = block.getEnd().subtract(block.getStart()) + 1;
ByteProvider bp = new MemoryByteProvider(memory, block.getStart());
return new ByteProviderWrapper(bp, 0, blockLen);
public static MemoryByteProvider createMemoryBlockByteProvider(Memory memory,
MemoryBlock block) {
return new MemoryByteProvider(memory, block.getStart(), block.getEnd());
}
/**
* Create a {@link ByteProvider} that starts at the beginning of the specified
* {@link Program program's} memory, containing either just the first
* memory block, or all memory blocks (of the same address space).
*
* @param program {@link Program} to read
* @param firstBlockOnly boolean flag, if true, only the first memory block will be accessible
* via the returned provider, if false, all memory blocks of the address space will be accessible
* @return new {@link MemoryByteProvider}, starting at program's minAddress
*/
public static MemoryByteProvider createProgramHeaderByteProvider(Program program,
boolean firstBlockOnly) {
return new MemoryByteProvider(program.getMemory(), program.getMinAddress(), firstBlockOnly);
}
/**
* Create a {@link ByteProvider} that starts at the beginning (e.g. 0) of the specified
* {@link Program program's} default address space memory, containing either the first memory
* block, or all memory blocks (of the same address space).
*
* @param program {@link Program} to read
* @param firstBlockOnly boolean flag, if true, only the first memory block will be accessible
* via the returned provider, if false, all memory blocks of the address space will be accessible
* @return new {@link MemoryByteProvider}, starting at program's minAddress
*/
public static MemoryByteProvider createDefaultAddressSpaceByteProvider(Program program,
boolean firstBlockOnly) {
return new MemoryByteProvider(program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace().getMinAddress(), firstBlockOnly);
}
protected Memory memory;
protected Address baseAddress;
protected long maxOffset; // max valid offset, inclusive
protected boolean isEmtpy; // empty is tracked separately because maxOffset == 0 does not mean empty
/**
* Constructs a new {@link MemoryByteProvider} for a specific {@link AddressSpace}. Bytes will be
* provided starting at address 0 in the space.
* Constructs a new {@link MemoryByteProvider} for a specific {@link AddressSpace}. Bytes
* will be provided relative to the minimum address (typically 0) in the space, and ranges
* to the highest address in the same address space currently found in the memory map.
* <p>
*
*
* @param memory the {@link Memory}
* @param space the {@link AddressSpace}
*/
public MemoryByteProvider(Memory memory, AddressSpace space) {
this(memory, space.getAddress(0));
this(memory, space.getMinAddress());
}
/**
* Constructs a new {@link MemoryByteProvider} relative to the specified base address.
* Constructs a new {@link MemoryByteProvider} relative to the specified base address,
* containing the address range to the highest address in the same address space currently
* found in the memory map.
*
* @param memory the {@link Memory}
* @param baseAddress the base address
*/
public MemoryByteProvider(Memory memory, Address baseAddress) {
this.memory = memory;
this.baseAddress = baseAddress;
this(memory, baseAddress, false);
}
/**
* Converts an index into this ByteProvider into an {@link Address}.
* <p>
* Constructs a new {@link MemoryByteProvider} relative to the specified base address,
* containing the address range to the end of the first memory block, or the highest address
* in the same address space, currently found in the memory map.
*
* @param index absolute index in this ByteProvider to convert into an Address
* @return {@link Address}
* @throws AddressOutOfBoundsException if wrapping is not supported by the
* corresponding address space and the addition causes an out-of-bounds
* error
* @param memory the {@link Memory}
* @param baseAddress the base address
* @param firstBlockOnly boolean flag, if true, only the first memory block will be accessible,
* if false, all memory blocks of the address space will be accessible
*/
public Address getAddress(long index) {
return baseAddress.add(index);
public MemoryByteProvider(Memory memory, Address baseAddress, boolean firstBlockOnly) {
this(memory, baseAddress, firstBlockOnly
? findEndOfBlock(memory, baseAddress)
: findAddressSpaceMax(memory, baseAddress));
}
/**
* Constructs a new {@link MemoryByteProvider} relative to the specified base address, with
* the specified length.
*
* @param memory the {@link Memory}
* @param baseAddress the base address
* @param maxAddress the highest address accessible by this provider (inclusive), or null
* if there is no memory
*/
private MemoryByteProvider(Memory memory, Address baseAddress, Address maxAddress) {
this.memory = memory;
this.baseAddress = baseAddress;
this.maxOffset = maxAddress != null
? maxAddress.subtract(baseAddress)
: 0;
this.isEmtpy = maxAddress == null;
}
private Address getAddress(long index) throws IOException {
if (index == 0) {
return baseAddress;
}
long base = baseAddress.getOffset();
long newAddress = base + index;
if (Long.compareUnsigned(base, newAddress) > 0) {
throw new IOException("Invalid index: %s".formatted(Long.toUnsignedString(index)));
}
return baseAddress.getNewAddress(newAddress);
}
/**
* Returns the address of the first byte of this provider.
*
* @return address of the first byte returned by this provider (at index 0)
*/
public Address getStartAddress() {
return baseAddress;
}
/**
* Returns the address of the last byte of this provider.
*
* @return address of the last byte returned by this provider
*/
public Address getEndAddress() {
return baseAddress.getNewAddress(baseAddress.getOffset() + maxOffset);
}
/**
* Returns the address range of the bytes of this provider.
*
* @return address range of first byte to last byte of this provider
*/
public AddressSetView getAddressSet() {
return new AddressSet(baseAddress, getEndAddress());
}
@Override
public InputStream getInputStream(long index) throws IOException {
return new MemoryByteProviderInputStream(memory, baseAddress.add(index));
public boolean isEmpty() {
return isEmtpy;
}
@Override
@ -100,28 +221,36 @@ public class MemoryByteProvider implements ByteProvider {
@Override
public long length() throws IOException {
MemoryBlock block = memory.getBlock(baseAddress);
if (block == null || !block.isInitialized()) {
if (isEmtpy) {
return 0;
}
return block.getEnd().subtract(baseAddress) + 1;
// clamp the max length to Long.MAX_VALUE
return Long.compareUnsigned(maxOffset, Long.MAX_VALUE - 1) >= 0
? Long.MAX_VALUE
: maxOffset + 1;
}
@Override
public boolean isValidIndex(long index) {
// this method treats the index as an unsigned int64, and will give accurate results
// for the entire range of the underlying AddressSpace
try {
Address indexAddress = baseAddress.add(index);
return memory.contains(indexAddress);
if (isEmtpy || Long.compareUnsigned(index, maxOffset) > 0) {
return false;
}
return memory.contains(getAddress(index));
}
catch (AddressOutOfBoundsException e) {
catch (IOException | AddressOutOfBoundsException e) {
return false;
}
}
@Override
public byte readByte(long index) throws IOException {
ensureBounds(index, 1);
try {
return memory.getByte(baseAddress.add(index));
return memory.getByte(getAddress(index));
}
catch (Exception e) {
throw new IOException(e.getMessage());
@ -130,11 +259,13 @@ public class MemoryByteProvider implements ByteProvider {
@Override
public byte[] readBytes(long index, long length) throws IOException {
ensureBounds(index, length);
try {
byte[] bytes = new byte[(int) length];
int nRead = memory.getBytes(baseAddress.add(index), bytes);
int nRead = memory.getBytes(getAddress(index), bytes);
if (nRead != length) {
throw new IOException("Unable to read " + length + " bytes at index " + index);
throw new IOException("Unable to read %d bytes at index %s".formatted(length,
Long.toUnsignedString(index)));
}
return bytes;
}
@ -150,4 +281,70 @@ public class MemoryByteProvider implements ByteProvider {
public void close() {
// don't do anything for now
}
//--------------------------------------------------------------------------------------------
private void ensureBounds(long index, long length) throws IOException {
// ensure length is valid
if (length < 0 || length > Integer.MAX_VALUE) {
throw new IOException(
"Unable to read more than Integer.MAX_VALUE bytes in one operation: %s"
.formatted(Long.toUnsignedString(length)));
}
if (index == 0 && length == 0) {
return; // success for read of 0 bytes at offset 0
}
// ensure read start index is valid
if (isEmtpy || Long.compareUnsigned(index, maxOffset) > 0) {
throw new EOFException("Invalid index: %s".formatted(Long.toUnsignedString(index)));
}
// NOTE: there should be a +1 on "remaining" to accurately model the count of remaining bytes
// Because it could cause an overflow, adjust "length" by -1 instead
long remaining = maxOffset - index /* + 1 -> becomes length - 1 */;
// ensure length of read is within bounds
if (length != 0 && Long.compareUnsigned(length - 1, remaining) > 0) {
throw new EOFException(
"Unable to read past EOF: %s, %d".formatted(Long.toUnsignedString(index), length));
}
}
private static Address findEndOfBlock(Memory memory, Address minAddr) {
MemoryBlock block = memory.getBlock(minAddr);
if (block != null) {
// address was inside a block, return it's end
return block.getEnd();
}
// address was outside all blocks. try to find a block that contains it and return its end
AddressSpace space = minAddr.getAddressSpace();
for (MemoryBlock block2 : memory.getBlocks()) {
Address end = block2.getEnd();
if (end.getAddressSpace().equals(space) && end.compareTo(minAddr) >= 0) {
return end;
}
}
return null;
}
private static Address findAddressSpaceMax(Memory memory, Address minAddr) {
if (minAddr == null) {
return null;
}
AddressSpace space = minAddr.getAddressSpace();
Address maxAddr = null;
for (AddressRange range : memory.getAddressRanges()) {
if (!range.getAddressSpace().equals(space)) {
continue;
}
Address rangeEnd = range.getMaxAddress();
if (rangeEnd.compareTo(minAddr) >= 0 &&
(maxAddr == null || rangeEnd.compareTo(maxAddr) >= 0)) {
maxAddr = rangeEnd;
}
}
return maxAddr;
}
}

View file

@ -1,76 +0,0 @@
/* ###
* 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.
* 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.app.util.bin;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.Memory;
import java.io.IOException;
import java.io.InputStream;
class MemoryByteProviderInputStream extends InputStream {
private Memory memory;
private Address startAddress;
private Address address;
MemoryByteProviderInputStream(Memory memory, Address address) {
this.memory = memory;
this.startAddress = address;
this.address = address;
}
@Override
public int read() throws IOException {
try {
byte b = memory.getByte(address);
address = address.add(1);
return b & 0xff;
}
catch (Exception e) {
throw new IOException(e.getMessage());
}
}
@Override
public int read(byte [] b, int off, int len) throws IOException {
try {
int nRead = memory.getBytes(address, b, off, len);
address = address.add(len);
return nRead;
}
catch (Exception e) {
throw new IOException(e.getMessage());
}
}
@Override
public int available() throws IOException {
return (int)memory.getMaxAddress().subtract(address);
}
@Override
public synchronized void reset() throws IOException {
address = startAddress;
}
@Override
public void close() throws IOException {
super.close();
memory = null;
address = null;
}
}

View file

@ -849,7 +849,7 @@ public class DIEAggregate {
? getCompilationUnit().getCompileUnit().getLowPC().longValue()
: 0L;
while (reader.getPointerIndex() < reader.length()) {
while (reader.hasNext()) {
// Read the beginning and ending addresses
Number beginning = DWARFUtil.readAddress(reader, pointerSize);
Number ending = DWARFUtil.readAddress(reader, pointerSize); // dwarf end addrs are exclusive

View file

@ -15,9 +15,10 @@
*/
package ghidra.app.util.bin.format.dwarf4;
import java.io.IOException;
import java.util.*;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.dwarf4.DWARFUtil.LengthResult;
import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
@ -195,7 +196,7 @@ public class DWARFCompilationUnit {
private static boolean isAllZerosUntilEOF(BinaryReader reader) throws IOException {
reader = reader.clone();
while (reader.getPointerIndex() < reader.length()) {
while (reader.hasNext()) {
if (reader.readNextByte() != 0) {
return false;
}

View file

@ -31,8 +31,6 @@ import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException;
import ghidra.app.util.bin.format.dwarf4.external.ExternalDebugInfo;
import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.*;
import ghidra.app.util.opinion.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Program;
@ -289,12 +287,8 @@ public class DWARFProgram implements Closeable {
return false;
}
ByteProvider bp = br.getByteProvider();
if (bp instanceof MemoryByteProvider && bp.length() > 0) {
MemoryByteProvider mbp = (MemoryByteProvider) bp;
Address startAddr = mbp.getAddress(0);
Address endAddr = mbp.getAddress(mbp.length() - 1);
if (program.getRelocationTable().getRelocations(
new AddressSet(startAddr, endAddr)).hasNext()) {
if (bp instanceof MemoryByteProvider mbp && !mbp.isEmpty()) {
if (program.getRelocationTable().getRelocations(mbp.getAddressSet()).hasNext()) {
return true;
}
}
@ -584,7 +578,7 @@ public class DWARFProgram implements Closeable {
BinaryReader br = debugInfoBR;
br.setPointerIndex(0);
while (br.getPointerIndex() < br.getByteProvider().length()) {
while (br.hasNext()) {
monitor.checkCanceled();
monitor.setMessage("Bootstrapping DWARF Compilation Unit #" + compUnits.size());

View file

@ -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 +15,14 @@
*/
package ghidra.app.util.bin.format.macos.rm;
import java.util.*;
import java.io.IOException;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import java.util.*;
public class ResourceMap implements StructConverter {
private ResourceHeader copy;
private int handleToNextResourceMap;
@ -70,7 +70,7 @@ public class ResourceMap implements StructConverter {
private void parseResourceNameList(BinaryReader reader) throws IOException {
long start = _mapStartIndex + resourceNameListOffset;
reader.setPointerIndex(_mapStartIndex + resourceNameListOffset);
while (reader.getPointerIndex() < reader.length()) {
while (reader.hasNext()) {
long offset = reader.getPointerIndex();
int length = reader.readNextByte() & 0xff;
String name = reader.readNextAsciiString(length);
@ -125,6 +125,7 @@ public class ResourceMap implements StructConverter {
return _mapStartIndex;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
return StructConverterUtil.toDataType(ResourceMap.class);
}

View file

@ -0,0 +1,240 @@
/* ###
* 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.app.util.bin;
import static org.junit.Assert.assertEquals;
import java.io.EOFException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.*;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.task.TaskMonitor;
public class MemoryByteProviderTest extends AbstractGhidraHeadedIntegrationTest {
protected ProgramDB program;
protected AddressSpace space;
protected Memory memory;
protected TaskMonitor monitor = TaskMonitor.DUMMY;
private ProgramBuilder builder;
@Before
public void setUp() throws Exception {
builder = new ProgramBuilder(testName.getMethodName(), ProgramBuilder._X64, this);
program = builder.getProgram();
memory = program.getMemory();
space = program.getAddressFactory().getDefaultAddressSpace();
}
protected Address addr(long l) {
return space.getAddress(l);
}
private void setBlockStartEndBytes(MemoryBlock memblk, String start, String end)
throws Exception {
builder.setBytes(memblk.getStart().toString(true),
start.getBytes(StandardCharsets.US_ASCII));
byte[] endBytes = end.getBytes(StandardCharsets.US_ASCII);
builder.setBytes(memblk.getEnd().subtract(endBytes.length - 1).toString(true), endBytes);
}
private MemoryBlock addRam0() throws Exception {
MemoryBlock memblk = builder.createMemory(space.getName(), "0", 0x50);
setBlockStartEndBytes(memblk, "startram0\0", "endram0\0");
return memblk;
}
private MemoryBlock addRam1() throws Exception {
MemoryBlock memblk = builder.createMemory(space.getName(), "50", 0x50);
setBlockStartEndBytes(memblk, "startram1\0", "endram1\0");
return memblk;
}
private MemoryBlock addRam2() throws Exception {
MemoryBlock memblk = builder.createMemory(space.getName(), "a0", 0x50);
setBlockStartEndBytes(memblk, "startram2\0", "endram2\0");
return memblk;
}
private MemoryBlock addRamEnd() throws Exception {
MemoryBlock memblk = builder.createMemory(space.getName(), "ffffffffffffffb0", 0x50);
setBlockStartEndBytes(memblk, "highstart\0", "highend\0");
return memblk;
}
@After
public void tearDown() throws Exception {
builder.dispose();
}
@Test
public void testNoMemory() throws IOException {
MemoryByteProvider mbp = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
assertEquals(0, mbp.length());
mbp = MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
assertEquals(0, mbp.length());
}
@Test
public void testCreateProgramHeader_Offset() throws Exception {
addRam1();
MemoryByteProvider mbp = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(mbp, true);
assertEquals(0x50, mbp.length());
assertEquals("startram1", reader.readAsciiString(0));
}
@Test
public void testCreateDefaultAddressSpace_Offset() throws Exception {
addRam1();
MemoryByteProvider mbp =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(mbp, true);
assertEquals(0x50 + 0x50, mbp.length());
assertEquals("startram1", reader.readAsciiString(0x50));
}
@Test
public void testMinAddrNotInBlock() throws Exception {
addRam1();
MemoryByteProvider mbp = new MemoryByteProvider(memory, addr(1));
BinaryReader reader = new BinaryReader(mbp, true);
assertEquals(0x50 + 0x50 - 1, mbp.length());
assertEquals("startram1", reader.readAsciiString(0x50 - 1));
}
@Test
public void testMinAddrInBlock() throws Exception {
addRam1();
MemoryByteProvider mbp = new MemoryByteProvider(memory, addr(0x51));
BinaryReader reader = new BinaryReader(mbp, true);
assertEquals(0x50 - 1, mbp.length());
assertEquals(/* missing 's' */ "tartram1", reader.readAsciiString(0));
}
@Test
public void testMinAddrAfterBlock() throws Exception {
addRam1();
MemoryByteProvider mbp = new MemoryByteProvider(memory, addr(0x5000));
assertEquals(0, mbp.length());
}
@Test
public void testMultiblock_adjacent() throws Exception {
MemoryBlock blk1 = addRam1();
MemoryBlock blk2 = addRam2();
setBlockStartEndBytes(blk1, "blah", "aaaa");
setBlockStartEndBytes(blk2, "bbbb", "blah");
MemoryByteProvider mbp =
MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(mbp, true);
assertEquals(blk2.getEnd().getOffset() - blk1.getStart().getOffset() + 1, mbp.length());
assertEquals(0x61616161, reader.readInt(0x50 - 4));
assertEquals(0x62626262, reader.readInt(0x50));
assertEquals(0x62626161, reader.readInt(0x50 - 2));
}
@Test
public void testMultiblockLength_disjoint() throws Exception {
MemoryBlock blk0 = addRam0();
MemoryBlock blk2 = addRam2();
MemoryByteProvider mbp =
MemoryByteProvider.createProgramHeaderByteProvider(program, false);
assertEquals(blk2.getEnd().getOffset() - blk0.getStart().getOffset() + 1, mbp.length());
}
@Test
public void testLength_block_at_end_of_64bits() throws Exception {
MemoryBlock blk = addRamEnd();
MemoryByteProvider mbp =
MemoryByteProvider.createProgramHeaderByteProvider(program, false);
assertEquals(blk.getEnd().getOffset() - blk.getStart().getOffset() + 1, mbp.length());
}
@Test
public void testLength_all64bits() throws Exception {
addRam0();
addRamEnd();
MemoryByteProvider mbp =
MemoryByteProvider.createProgramHeaderByteProvider(program, false);
assertEquals(Long.MAX_VALUE, mbp.length());
}
@Test
public void testFull64bitAddressSpace() throws Exception {
addRamEnd();
MemoryByteProvider mbp =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(mbp, true);
assertEquals(Long.MAX_VALUE, mbp.length());
assertEquals("highstart", reader.readAsciiString(0xffffffffffffffb0L));
assertEquals("end", reader.readAsciiString(0xfffffffffffffffcL));
}
@Test(expected = EOFException.class)
public void testFull64bitAddressSpace_fail_when_wrap_string() throws Exception {
MemoryBlock blk = addRamEnd();
setBlockStartEndBytes(blk, "blah", "fail");
MemoryByteProvider mbp =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(mbp, true);
reader.readAsciiString(0xfffffffffffffffcL);
}
@Test(expected = EOFException.class)
public void testFull64bitAddressSpace_fail_when_wrap_int() throws Exception {
addRamEnd();
MemoryByteProvider mbp =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(mbp, true);
reader.readInt(0xfffffffffffffffeL);
}
@Test(expected = EOFException.class)
public void testEOFExceptionWhenCrossingMemBlockBoundary() throws Exception {
MemoryBlock blk1 = addRam1();
addRamEnd();
MemoryByteProvider mbp =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(mbp, true);
assertEquals("endram1", reader.readAsciiString(blk1.getEnd().getOffset() - 7));
setBlockStartEndBytes(blk1, "blah", "fail");
reader.readAsciiString(blk1.getEnd().getOffset() - 3);
}
}

View file

@ -32,9 +32,8 @@ public class BTreeAnnotationScript extends GhidraScript {
@Override
public void run() throws Exception {
Address address = currentProgram.getMinAddress();
ByteProvider provider = new MemoryByteProvider(currentProgram.getMemory(), address);
ByteProvider provider =
MemoryByteProvider.createProgramHeaderByteProvider(currentProgram, false);
BinaryReader reader = new BinaryReader(provider, false);

View file

@ -19,9 +19,7 @@ import java.io.IOException;
import ghidra.app.plugin.core.analysis.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.app.util.bin.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.file.analyzers.FileFormatAnalyzer;
import ghidra.program.model.address.Address;
@ -30,9 +28,7 @@ import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.NotFoundException;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
public class BootImageAnalyzer extends FileFormatAnalyzer implements AnalysisWorker {
@ -89,9 +85,7 @@ public class BootImageAnalyzer extends FileFormatAnalyzer implements AnalysisWor
TaskMonitor monitor)
throws Exception, CancelledException {
Address address = program.getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, true);
if (BootImageUtil.isBootImage(program)) {

View file

@ -58,7 +58,8 @@ public class AndroidBootLoaderAnalyzer extends AbstractAnalyzer {
AddressSpace addressSpace = program.getAddressFactory().getDefaultAddressSpace();
Address headerAddress = program.getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), headerAddress);
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
try {
AndroidBootLoaderHeader header = new AndroidBootLoaderHeader(reader);

View file

@ -74,8 +74,7 @@ public class DexCondenseFillerBytesAnalyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze(Program program) {
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
return DexConstants.isDexFile(provider) || CDexConstants.isCDEX(program);
}

View file

@ -49,8 +49,7 @@ public class DexExceptionHandlersAnalyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze(Program program) {
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
return DexConstants.isDexFile(provider) || CDexConstants.isCDEX(program);
}

View file

@ -65,8 +65,7 @@ public class DexHeaderFormatAnalyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze(Program program) {
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
return DexConstants.isDexFile(provider) || CDexConstants.isCDEX(program);
}

View file

@ -69,8 +69,7 @@ public class DexMarkupDataAnalyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze(Program program) {
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
return DexConstants.isDexFile(provider) || CDexConstants.isCDEX(program);
}

View file

@ -45,8 +45,7 @@ public class DexMarkupInstructionsAnalyzer extends FileFormatAnalyzer {
DexHeader header = analysisState.getHeader();
// Set-up reader for fill_array_data
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, true);
Listing listing = program.getListing();
@ -145,8 +144,7 @@ public class DexMarkupInstructionsAnalyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze(Program program) {
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
return DexConstants.isDexFile(provider) || CDexConstants.isCDEX(program);
}

View file

@ -18,29 +18,19 @@ package ghidra.file.formats.android.dex.analyzer;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.services.AnalysisPriority;
import ghidra.app.services.AnalyzerType;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.app.util.bin.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.file.analyzers.FileFormatAnalyzer;
import ghidra.file.formats.android.cdex.CDexConstants;
import ghidra.file.formats.android.dex.format.DexConstants;
import ghidra.file.formats.android.dex.format.PackedSwitchPayload;
import ghidra.file.formats.android.dex.format.SparseSwitchPayload;
import ghidra.file.formats.android.dex.format.*;
import ghidra.file.formats.android.dex.util.DexUtil;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.InstructionIterator;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.*;
import ghidra.util.task.TaskMonitor;
public class DexMarkupSwitchTableAnalyzer extends FileFormatAnalyzer {
@ -51,8 +41,7 @@ public class DexMarkupSwitchTableAnalyzer extends FileFormatAnalyzer {
monitor.setMaximum(set == null ? program.getMemory().getSize() : set.getNumAddresses());
monitor.setProgress(0);
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, true);
Listing listing = program.getListing();
@ -126,8 +115,7 @@ public class DexMarkupSwitchTableAnalyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze(Program program) {
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
return DexConstants.isDexFile(provider) || CDexConstants.isCDEX(program);
}

View file

@ -15,9 +15,7 @@
*/
package ghidra.file.formats.android.fbpk;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.app.util.bin.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.file.analyzers.FileFormatAnalyzer;
import ghidra.program.model.address.Address;
@ -59,7 +57,8 @@ public class FBPK_Analyzer extends FileFormatAnalyzer {
throws Exception {
Address headerAddress = program.getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), headerAddress);
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
try {
FBPK header = FBPK_Factory.getFBPK(reader);

View file

@ -15,9 +15,10 @@
*/
package ghidra.file.formats.android.lz4;
import java.io.*;
import java.util.*;
import java.io.*;
import org.apache.commons.compress.compressors.lz4.BlockLZ4CompressorInputStream;
import ghidra.app.util.bin.BinaryReader;
@ -89,7 +90,7 @@ public class LZ4ArchiveFileSystem extends GFileSystemBase {
upwtm.setMessage("Decompressing LZ4 archive...");
upwtm.setProgress(0);
while (reader.getPointerIndex() < reader.length()) {
while (reader.hasNext()) {
monitor.checkCanceled();
int compressedChunkSize = reader.readNextInt();

View file

@ -15,9 +15,10 @@
*/
package ghidra.file.formats.android.oat.bundle;
import java.io.IOException;
import java.util.*;
import java.io.IOException;
import org.apache.commons.io.FilenameUtils;
import ghidra.app.util.bin.*;
@ -89,6 +90,7 @@ public class FullOatBundle implements OatBundle {
return null;//could NOT find matching dex header, probably not imported yet
}
@Override
public ArtHeader getArtHeader() {
return artHeader;
}
@ -98,10 +100,12 @@ public class FullOatBundle implements OatBundle {
return oatHeader;
}
@Override
public List<DexHeader> getDexHeaders() {
return dexHeaders;
}
@Override
public VdexHeader getVdexHeader() {
return vdexHeader;
}
@ -208,7 +212,7 @@ public class FullOatBundle implements OatBundle {
try {
program = (Program) child.getDomainObject(this, true, true, monitor);
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
MemoryByteProvider.createProgramHeaderByteProvider(program, false);
return makeHeader(type, programName, provider, monitor);
}
catch (Exception e) {

View file

@ -17,16 +17,12 @@ package ghidra.file.formats.android.odex;
import ghidra.app.services.AnalysisPriority;
import ghidra.app.services.AnalyzerType;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.app.util.bin.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.file.analyzers.FileFormatAnalyzer;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.DWordDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StringDataType;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock;
@ -51,8 +47,7 @@ public class OdexHeaderFormatAnalyzer extends FileFormatAnalyzer {
block.setWrite(false);
block.setExecute(false);
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, true);
OdexHeader header = new OdexHeader(reader);
@ -80,8 +75,7 @@ public class OdexHeaderFormatAnalyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze(Program program) {
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
return OdexConstants.isOdexFile(provider);
}

View file

@ -15,8 +15,6 @@
*/
package ghidra.file.formats.android.vdex;
import java.io.IOException;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.program.model.address.Address;
@ -112,7 +110,7 @@ public final class VdexConstants {
for (MemoryBlock block : program.getMemory().getBlocks()) {
try (ByteProvider provider =
new MemoryByteProvider(program.getMemory(), block.getStart())) {
MemoryByteProvider.createMemoryBlockByteProvider(program.getMemory(), block)) {
String magic = new String(provider.readBytes(0, VdexConstants.MAGIC.length()));
if (VdexConstants.MAGIC.equals(magic)) {
return true;
@ -127,30 +125,21 @@ public final class VdexConstants {
}
public final static Address findVDEX(Program program) {
try {
if (program != null) {
for (MemoryBlock block : program.getMemory().getBlocks()) {
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), block.getStart());
try {
String magic =
new String(provider.readBytes(0, VdexConstants.MAGIC.length()));
if (VdexConstants.MAGIC.equals(magic)) {
return block.getStart();
}
}
catch (Exception e) {
//ignore
}
finally {
provider.close();
if (program != null) {
for (MemoryBlock block : program.getMemory().getBlocks()) {
try (ByteProvider provider = MemoryByteProvider
.createMemoryBlockByteProvider(program.getMemory(), block)) {
String magic =
new String(provider.readBytes(0, VdexConstants.MAGIC.length()));
if (VdexConstants.MAGIC.equals(magic)) {
return block.getStart();
}
}
catch (Exception e) {
//ignore
}
}
}
catch (IOException e) {
//ignore
}
return null;
}
}

View file

@ -49,7 +49,8 @@ public class Ext4Analyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze(Program program) {
ByteProvider provider = new MemoryByteProvider( program.getMemory(), program.getAddressFactory().getDefaultAddressSpace());
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, true);
int start = getSuperBlockStart(reader);
if( start == -1 ) {
@ -77,7 +78,8 @@ public class Ext4Analyzer extends FileFormatAnalyzer {
@Override
public boolean analyze(Program program, AddressSetView set,
TaskMonitor monitor, MessageLog log) throws Exception {
ByteProvider provider = new MemoryByteProvider( program.getMemory(), program.getAddressFactory().getDefaultAddressSpace());
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, true);
int start = getSuperBlockStart(reader);
int groupStart = 0;

View file

@ -15,23 +15,20 @@
*/
package ghidra.file.formats.ext4;
import java.io.IOException;
import java.util.List;
import java.io.IOException;
import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.services.ProgramManager;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.app.util.bin.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.file.analyzers.FileFormatAnalyzer;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.exception.DuplicateNameException;
@ -63,7 +60,8 @@ public class NewExt4Analyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze( Program program ) {
ByteProvider provider = new MemoryByteProvider( program.getMemory( ), program.getAddressFactory( ).getDefaultAddressSpace( ) );
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader( provider, true );
int start = getSuperBlockStart( reader );
if ( start == -1 ) {

View file

@ -15,17 +15,17 @@
*/
package ghidra.file.formats.gzip;
import java.util.Arrays;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.program.model.listing.Program;
import java.util.Arrays;
public class GZipUtil {
public final static boolean isGZip( Program program ) {
ByteProvider provider = new MemoryByteProvider( program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace() );
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, true);
return isGZip( provider );
}

View file

@ -27,33 +27,38 @@ import ghidra.util.task.TaskMonitor;
public class Apple8900Analyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze(Program program) {
return Apple8900Util.is8900(program);
}
@Override
public boolean getDefaultEnablement(Program program) {
return Apple8900Util.is8900(program);
}
@Override
public String getDescription() {
return "Annotates an Apple 8900 file.";
}
@Override
public String getName() {
return "Apple 8900 Annotation";
}
@Override
public boolean isPrototype() {
return true;
}
@Override
public boolean analyze(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws Exception {
monitor.setMessage("Processing Apple 8900 header...");
ByteProvider provider =
new MemoryByteProvider(program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace());
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, true);
Apple8900Header header = new Apple8900Header(reader);

View file

@ -15,6 +15,8 @@
*/
package ghidra.file.formats.ios.dmg;
import java.util.Arrays;
import ghidra.app.plugin.core.analysis.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.util.bin.*;
@ -28,8 +30,6 @@ import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import java.util.Arrays;
public class DmgAnalyzer extends FileFormatAnalyzer implements AnalysisWorker {
@Override
@ -44,7 +44,7 @@ public class DmgAnalyzer extends FileFormatAnalyzer implements AnalysisWorker {
throws Exception, CancelledException {
Address address = program.getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, false);
DmgHeader header = new DmgHeaderV2(reader);
@ -67,22 +67,27 @@ public class DmgAnalyzer extends FileFormatAnalyzer implements AnalysisWorker {
return getName();
}
@Override
public boolean canAnalyze(Program program) {
return DmgUtil.isDMG(program);
}
@Override
public boolean getDefaultEnablement(Program program) {
return DmgUtil.isDMG(program);
}
@Override
public String getDescription() {
return "Annotates an DMG file.";
}
@Override
public String getName() {
return "DMG";
}
@Override
public boolean isPrototype() {
return true;
}

View file

@ -39,8 +39,7 @@ public class DyldCacheAnalyzer extends FileFormatAnalyzer {
throws Exception {
Address headerAddress = program.getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), headerAddress);
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
DyldArchitecture architecture = DyldArchitecture.getArchitecture(provider);
if (architecture == null) {
log.appendMsg("Invalid DYLD cache file.");

View file

@ -43,8 +43,7 @@ public class iBootImAnalyzer extends FileFormatAnalyzer implements AnalysisWorke
throws Exception, CancelledException {
Address address = program.getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
iBootImHeader header = new iBootImHeader(provider);
if (!header.getSignature().equals(iBootImConstants.SIGNATURE)) {
@ -69,22 +68,27 @@ public class iBootImAnalyzer extends FileFormatAnalyzer implements AnalysisWorke
return getName();
}
@Override
public boolean canAnalyze(Program program) {
return iBootImUtil.isiBootIm(program);
}
@Override
public boolean getDefaultEnablement(Program program) {
return iBootImUtil.isiBootIm(program);
}
@Override
public String getDescription() {
return "Annotates an iBoot Image (iBootIm) file.";
}
@Override
public String getName() {
return "iBoot Image (iBootIm) Annotation";
}
@Override
public boolean isPrototype() {
return true;
}

View file

@ -27,6 +27,7 @@ import ghidra.util.task.TaskMonitor;
public class Img2Analyzer extends FileFormatAnalyzer {
@Override
public boolean canAnalyze(Program program) {
try {
return Img2Util.isIMG2(program);
@ -37,28 +38,32 @@ public class Img2Analyzer extends FileFormatAnalyzer {
return false;
}
@Override
public boolean getDefaultEnablement(Program program) {
return Img2Util.isIMG2(program);
}
@Override
public String getDescription() {
return "Annotates an IMG2 file.";
}
@Override
public String getName() {
return "IMG2 Annotation";
}
@Override
public boolean isPrototype() {
return true;
}
@Override
public boolean analyze(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws Exception {
ByteProvider provider =
new MemoryByteProvider(program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace());
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, true);
Img2 header = new Img2(reader);

View file

@ -15,6 +15,8 @@
*/
package ghidra.file.formats.ios.img3;
import java.util.List;
import ghidra.app.plugin.core.analysis.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.util.bin.*;
@ -28,30 +30,34 @@ import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import java.util.List;
public class Img3Analyzer extends FileFormatAnalyzer implements AnalysisWorker {
@Override
public boolean canAnalyze(Program program) {
return Img3Util.isIMG3(program);
}
@Override
public boolean getDefaultEnablement(Program program) {
return Img3Util.isIMG3(program);
}
@Override
public String getDescription() {
return "Annotates an IMG3 file.";
}
@Override
public String getName() {
return "IMG3 Annotation";
}
@Override
public boolean isPrototype() {
return true;
}
@Override
public boolean analyze(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws Exception {
AutoAnalysisManager manager = AutoAnalysisManager.getAnalysisManager(program);
@ -63,7 +69,7 @@ public class Img3Analyzer extends FileFormatAnalyzer implements AnalysisWorker {
throws Exception, CancelledException {
Address address = program.getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, true);
Img3 header = new Img3(reader);

View file

@ -1,488 +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.file.formats.iso9660;
import java.io.IOException;
import java.util.*;
import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.cmd.data.CreateDataCmd;
import ghidra.app.cmd.data.CreateStringCmd;
import ghidra.app.services.AbstractAnalyzer;
import ghidra.app.services.AnalyzerType;
import ghidra.app.util.bin.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.BinaryLoader;
import ghidra.framework.options.Options;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
public class ISO9660Analyzer extends AbstractAnalyzer {
private enum Offset {
Offset1, //0x8001
Offset2, //0x8801
Offset3, //0x9001
NotFound
}
public ISO9660Analyzer() {
super("ISO9660 File Format Annotation", "Annotates an ISO9660 File Format",
AnalyzerType.BYTE_ANALYZER);
super.setPrototype();
}
@Override
public boolean canAnalyze(Program program) {
Offset result = checkSignatures(program);
if (result.equals(Offset.NotFound)) {
return false;
}
return true;
}
private Offset checkSignatures(Program program) {
int magicLen = ISO9660Constants.MAGIC_BYTES.length;
byte[] signatureArray = new byte[magicLen];
try {
Options options = program.getOptions("Program Information");
String format = options.getString("Executable Format", null);
if (!BinaryLoader.BINARY_NAME.equals(format)) {
return Offset.NotFound;
}
MemoryBlock[] blocks = program.getMemory().getBlocks();
if (blocks.length != 1) {
return Offset.NotFound;
}
AddressSpace addressSpace = program.getAddressFactory().getDefaultAddressSpace();
if (!(blocks[0].getStart().getAddressSpace().equals(addressSpace))) {
return Offset.NotFound;
}
long blockSize = blocks[0].getSize();
//block must start at zero
if (blocks[0].getStart().getOffset() != 0L) {
return Offset.NotFound;
}
//is the block initialized
if (!blocks[0].isInitialized()) {
return Offset.NotFound;
}
ByteProvider provider = new MemoryByteProvider(program.getMemory(), addressSpace);
BinaryReader reader = new BinaryReader(provider, true);
//Make sure that the current programs max offset is at least big enough to check
//for the ISO's max address location of a signature
if (blockSize < ISO9660Constants.MIN_ISO_LENGTH1) {
return Offset.NotFound;
}
//Check first possible signature location
reader.setPointerIndex(ISO9660Constants.SIGNATURE_OFFSET1_0x8001);
signatureArray = reader.readNextByteArray(magicLen);
if (Arrays.equals(signatureArray, ISO9660Constants.MAGIC_BYTES)) {
//Where to start the reader during mark up
return Offset.Offset1;
}
if (blockSize < ISO9660Constants.MIN_ISO_LENGTH2) {
return Offset.NotFound;
}
//Check second possible signature location
reader.setPointerIndex(ISO9660Constants.SIGNATURE_OFFSET2_0x8801);
signatureArray = reader.readNextByteArray(magicLen);
if (Arrays.equals(signatureArray, ISO9660Constants.MAGIC_BYTES)) {
//Where to start the reader during mark up
return Offset.Offset2;
}
if (blockSize < ISO9660Constants.MIN_ISO_LENGTH3) {
return Offset.NotFound;
}
//Check third possible signature location
reader.setPointerIndex(ISO9660Constants.SIGNATURE_OFFSET3_0x9001);
signatureArray = reader.readNextByteArray(magicLen);
if (Arrays.equals(signatureArray, ISO9660Constants.MAGIC_BYTES)) {
//Where to start the reader during mark up
return Offset.Offset3;
}
}
catch (Exception e) {
Msg.error(this, "Error when checking for ISO9660 file signatures", e);
}
//Signature is not found at any of the three possible address locations
return Offset.NotFound;
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
ByteProvider provider = new MemoryByteProvider(program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace());
BinaryReader reader = new BinaryReader(provider, true);
try {
Offset signatureOffset = checkSignatures(program);
setPointerOffset(signatureOffset, reader);
monitor.setMessage("Processing ISO9660 Header");
//Get the full header (contains all volume descriptors)
ISO9660Header isoHeader = new ISO9660Header(reader);
//Get the list of volumes from the header
List<ISO9660BaseVolume> volumes = isoHeader.getVolumeDescriptorSet();
//Set the overall plate comment at the top of this file
setPlateComment(program, toAddress(program, 0), isoHeader.toString());
//Create a new module for the volume descriptor fragments
ProgramModule descriptorModule =
program.getListing().getDefaultRootModule().createModule("Volume Descriptors");
//For each volume, set the volumes plate comment and data at the address it exists
setDescriptorData(program, volumes, descriptorModule);
processPathTables(isoHeader, reader, program);
//Create an alignment over the null characters from start to the first volume
int offset = getOffsetValue(signatureOffset);
program.getListing().createData(toAddress(program, 0), new AlignmentDataType(),
offset - 1);
ISO9660VolumeDescriptor pvd = isoHeader.getPrimaryVolumeDescriptor();
ISO9660Directory entryDir = isoHeader.getPrimaryDirectory();
int logicalBlockSize = pvd.getLogicalBlockSizeLE();
List<ISO9660Directory> dirList =
createDirectoryList(reader, entryDir, logicalBlockSize);
createDirectories(reader, program, dirList, logicalBlockSize);
}
catch (Exception e) {
log.appendException(e);
return false;
}
return true;
}
private void setPointerOffset(Offset offset, BinaryReader reader) {
if (offset.equals(Offset.Offset1)) {
reader.setPointerIndex(ISO9660Constants.SIGNATURE_OFFSET1_0x8001 - 1);
}
else if (offset.equals(Offset.Offset2)) {
reader.setPointerIndex(ISO9660Constants.SIGNATURE_OFFSET2_0x8801 - 1);
}
else {
reader.setPointerIndex(ISO9660Constants.SIGNATURE_OFFSET3_0x9001 - 1);
}
}
private int getOffsetValue(Offset offsetEnum) {
if (offsetEnum.equals(Offset.Offset1)) {
return ISO9660Constants.SIGNATURE_OFFSET1_0x8001;
}
else if (offsetEnum.equals(Offset.Offset2)) {
return ISO9660Constants.SIGNATURE_OFFSET2_0x8801;
}
else {
return ISO9660Constants.SIGNATURE_OFFSET3_0x9001;
}
}
private void setDescriptorData(Program program, List<ISO9660BaseVolume> volumes,
ProgramModule descriptorModule) throws DuplicateNameException, IOException, Exception {
for (ISO9660BaseVolume descriptor : volumes) {
long volumeIndex = descriptor.getVolumeIndex();
DataType descriptorDataType = descriptor.toDataType();
Address volumeAddress = toAddress(program, volumeIndex);
Data descriptorData =
createData(program, toAddress(program, volumeIndex), descriptorDataType);
setPlateComment(program, volumeAddress, descriptor.toString());
//Add fragment to module
createFragment(program, descriptorModule, descriptorDataType.getName(),
descriptorData.getMinAddress(), descriptorData.getMaxAddress().next());
}
}
/*
* Process the normal and supplementary path tables in the binary
*/
private void processPathTables(ISO9660Header isoHeader, BinaryReader reader, Program program)
throws DuplicateNameException {
//Create module to add path table fragments to
ProgramModule pathTableModule =
program.getListing().getDefaultRootModule().createModule("Path Tables");
try {
//Get the tables which hold the index and size pairs of path tables
//for little-endian values
HashMap<Integer, Short> typeLTable = isoHeader.getTypeLIndexSizeTable();
createPathTableData(reader, program, pathTableModule, typeLTable, true);
//Get the tables which hold the index and size pairs of path tables
//for big-endian values
HashMap<Integer, Short> typeMTable = isoHeader.getTypeMIndexSizeTable();
createPathTableData(reader, program, pathTableModule, typeMTable, false);
//Get the tables which hold the index and size of supplementary path tables
//for little-endian values
HashMap<Integer, Short> supplTypeLTable = isoHeader.getSupplTypeLIndexSizeTable();
createPathTableData(reader, program, pathTableModule, supplTypeLTable, true);
//Get the tables which hold the index and size of supplementary path tables
//for big-endian values
HashMap<Integer, Short> supplTypeMTable = isoHeader.getSupplTypeMIndexSizeTable();
createPathTableData(reader, program, pathTableModule, supplTypeMTable, false);
}
catch (Exception e) {
e.printStackTrace();
}
}
/*
* From a given parent directory create each child directory
* under that parent directory and add them to a list
*/
private List<ISO9660Directory> createDirectoryList(BinaryReader reader,
ISO9660Directory parentDir, long blockSize) throws IOException {
List<ISO9660Directory> directoryList = new ArrayList<>();
ISO9660Directory childDir = null;
//Get location from parent into child directory
long dirIndex = parentDir.getLocationOfExtentLE() * blockSize;
long endIndex = dirIndex + parentDir.getDataLengthLE();
//while there is still more data in the current directory level
while (dirIndex < endIndex) {
reader.setPointerIndex(dirIndex);
//If the next byte is not zero then create the directory
if (reader.peekNextByte() != 0) {
childDir = new ISO9660Directory(reader, parentDir);
directoryList.add(childDir);
}
//Otherwise there is a gap in the data so keep looking forward
//while still under the end index and create directory when data is
//reached
else {
while (reader.peekNextByte() == 0) {
//keep reading if all zeros until non zero is met or
//end index reached
if (reader.getPointerIndex() < endIndex) {
reader.readNextByte();
}
else {
break;
}
}
//Create the data once the reader finds the next position
//and not reached end index
if (reader.getPointerIndex() < endIndex) {
childDir = new ISO9660Directory(reader, parentDir);
dirIndex = childDir.getVolumeIndex();
directoryList.add(childDir);
}
}
dirIndex += childDir.getDirectoryRecordLength();
}
return directoryList;
}
/*
* Recurses though each level of a directory structure
* in a depth-first manner
* and creates each directory also marking them in the binary
*/
private void createDirectories(BinaryReader reader, Program program,
List<ISO9660Directory> directoryList, long blockSize)
throws DuplicateNameException, Exception {
Address volumeAddress;
//If the directory size is over two then there are actual
//new directories in that level. The first two are always
//the 'self' directory and the parent directory
if (directoryList.size() > 2) {
ISO9660Directory selfDir = null;
ISO9660Directory parentDir = null;
// The 'self' describing directory entry
selfDir = directoryList.remove(0);
volumeAddress = toAddress(program, selfDir.getVolumeIndex());
createDataAndPlateComment(program, selfDir, volumeAddress);
// The parent directory
parentDir = directoryList.remove(0);
volumeAddress = toAddress(program, parentDir.getVolumeIndex());
createDataAndPlateComment(program, parentDir, volumeAddress);
//For everything else not a self or parent directory
for (ISO9660Directory dir : directoryList) {
//If this directory is not pointing to a file
//Create the directory data
if (selfDir.isDirectoryFlagSet()) {
volumeAddress = toAddress(program, dir.getVolumeIndex());
setPlateComment(program, volumeAddress, dir.toString());
DataType volumeDataType = dir.toDataType();
createData(program, volumeAddress, volumeDataType);
//If the directory is a new level of directories
//recurse down into the next level
if (dir.isDirectoryFlagSet()) {
List<ISO9660Directory> dirs;
dirs = createDirectoryList(reader, dir, blockSize);
createDirectories(reader, program, dirs, blockSize);
}
}
}
}
return;
}
private void createDataAndPlateComment(Program program, ISO9660Directory dir,
Address volumeAddress) throws DuplicateNameException, IOException, Exception {
setPlateComment(program, volumeAddress, dir.toString());
createData(program, volumeAddress, dir.toDataType());
}
/*
* Creates path table plate comments and lays mark up data down on the binary
*/
private void createPathTableData(BinaryReader reader, Program program, ProgramModule module,
HashMap<Integer, Short> pathTableMap, boolean littleEndian) throws Exception {
//Enumeration over the indexes of the path tables in the table
Set<Integer> pathTableIndexes = pathTableMap.keySet();
Iterator<Integer> pathIter = pathTableIndexes.iterator();
while (pathIter.hasNext()) {
//Index of current path table
int pathTableIndex = pathIter.next();
//Logical block size of current path table
short logicalBlockSize = pathTableMap.get(pathTableIndex);
//Calculate address from logical index
int pathAddress = logicalBlockSize * pathTableIndex;
//Move reader to the path table address
reader.setPointerIndex(pathAddress);
ISO9660PathTable pathTable = new ISO9660PathTable(reader, littleEndian);
DataType pathTableDataType = pathTable.toDataType();
Address volumeAddress = toAddress(program, pathTable.getVolumeIndex());
setPlateComment(program, volumeAddress, pathTable.toString());
Data pathTableData = createData(program, volumeAddress, pathTableDataType);
createFragment(program, module, pathTableDataType.getName(),
pathTableData.getMinAddress(), pathTableData.getMaxAddress().next());
}
}
/*
* Marks up the binary with data
*/
private Data createData(Program program, Address address, DataType datatype) throws Exception {
if (datatype instanceof StringDataType) {
CreateStringCmd cmd = new CreateStringCmd(address);
if (!cmd.applyTo(program)) {
throw new RuntimeException(cmd.getStatusMsg());
}
}
else {
CreateDataCmd cmd = new CreateDataCmd(address, datatype);
if (!cmd.applyTo(program)) {
throw new RuntimeException(cmd.getStatusMsg());
}
}
return program.getListing().getDefinedDataAt(address);
}
private Address toAddress(Program program, long offset) {
return program.getAddressFactory().getDefaultAddressSpace().getAddress(offset);
}
private boolean setPlateComment(Program program, Address address, String comment) {
SetCommentCmd cmd = new SetCommentCmd(address, CodeUnit.PLATE_COMMENT, comment);
return cmd.applyTo(program);
}
private ProgramFragment createFragment(Program program, ProgramModule module,
String fragmentName, Address start, Address end) throws Exception {
ProgramFragment fragment = getFragment(module, fragmentName);
if (fragment == null) {
fragment = module.createFragment(fragmentName);
}
fragment.move(start, end.subtract(1));
return fragment;
}
private ProgramFragment getFragment(ProgramModule module, String fragmentName) {
Group[] groups = module.getChildren();
if (groups != null) {
for (Group group : groups) {
if (group.getName().equals(fragmentName) && group instanceof ProgramFragment) {
return (ProgramFragment) group;
}
}
}
return null;
}
}

View file

@ -1,105 +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.file.formats.iso9660;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* Parent class used for all other types of volume descriptors
*/
public class ISO9660BaseVolume implements StructConverter {
private long volumeIndex;
private byte typeCode;
private byte[] identifier;
private byte version;
public ISO9660BaseVolume(BinaryReader reader) throws IOException {
volumeIndex = reader.getPointerIndex();
typeCode = reader.readNextByte();
identifier = reader.readNextByteArray(ISO9660Constants.MAGIC_BYTES.length);
version = reader.readNextByte();
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure struc = new StructureDataType("ISO9660VolumeDescriptor", 0);
struc.add(BYTE, "Type Code", "Type of volume descriptor");
struc.add(new ArrayDataType(BYTE, identifier.length, 1), "Standard Identifier",
"Always 'CD001'");
struc.add(BYTE, "Version", "Always 0x01");
return struc;
}
/**
* Creates a string representation of this class filling in field specifics
* when applicable.
* @return the string representation of this class
*/
@Override
public String toString() {
StringBuffer buff = new StringBuffer();
buff.append("Type Code: 0x" + Integer.toHexString(typeCode) + " => " + getTypeCodeString() +
"\n");
buff.append("Standard Identifier: " + new String(identifier).trim() + "\n");
buff.append("Version: 0x" + Integer.toHexString(version) + "\n");
return buff.toString();
}
public String getTypeCodeString() {
switch (typeCode) {
case ISO9660Constants.VOLUME_DESC_BOOT_RECORD:
return "Boot Record";
case ISO9660Constants.VOLUME_DESC_PRIMARY_VOLUME_DESC:
return "Primary Volume Descriptor";
case ISO9660Constants.VOLUME_DESC_SUPPL_VOLUME_DESC:
return "Supplementary Volume Descriptor";
case ISO9660Constants.VOLUME_PARTITION_DESC:
return "Volume Partition Descriptor";
case ISO9660Constants.VOLUME_DESC_SET_TERMINATOR:
return "Volume Descriptor Set Terminator";
default:
return "";
}
}
public byte getTypeCode() {
return typeCode;
}
public byte[] getIdentifier() {
return identifier;
}
public byte getVersion() {
return version;
}
public long getVolumeIndex() {
return volumeIndex;
}
}

View file

@ -1,86 +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.file.formats.iso9660;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
public class ISO9660BootRecordVolumeDescriptor extends ISO9660BaseVolume {
private byte[] bootSystemIdentifier;// Length 0x20
private byte[] bootIdentifier; // Length 0x20
private byte[] bootSystemUse; // Length 0x7b9;
public ISO9660BootRecordVolumeDescriptor(BinaryReader reader) throws IOException {
super(reader);
bootSystemIdentifier = reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_32);
bootIdentifier = reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_32);
bootSystemUse = reader.readNextByteArray(ISO9660Constants.BOOT_SYSTEM_USE_LENGTH);
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure struc = new StructureDataType("ISO9600BootRecord", 0);
struc.add(BYTE, "Type", "Volume Descriptor Type");
struc.add(new ArrayDataType(BYTE, super.getIdentifier().length, 1), "Identifier",
"Identifier");
struc.add(BYTE, "Version", "Volume Descriptor Version");
struc.add(new ArrayDataType(BYTE, bootSystemIdentifier.length, 1),
"Boot System Identifier", "ID of the system which can act on and boot the system");
struc.add(new ArrayDataType(BYTE, bootIdentifier.length, 1), "Boot Identifier",
"Identification of the boot system");
struc.add(new ArrayDataType(BYTE, bootSystemUse.length, 1), "Boot System Use",
"Custom - used by the boot system");
return struc;
}
/**
* Creates a string representation of this class filling in field specifics
* when applicable.
* @return the string representation of this class
*/
@Override
public String toString() {
StringBuffer buff = new StringBuffer();
buff.append("Type: 0x" + Integer.toHexString(super.getTypeCode()) + " => " +
getTypeCodeString() + "\n");
buff.append("Identifier: " + new String(super.getIdentifier()).trim() + "\n");
buff.append("Version: 0x" + Integer.toHexString(super.getVersion()) + "\n");
buff.append("Boot System Identifier: " + new String(bootSystemIdentifier).trim() + "\n");
buff.append("Boot Identifier: " + new String(bootIdentifier).trim() + "\n");
return buff.toString();
}
public byte[] getBootSystemIdentifier() {
return bootSystemIdentifier;
}
public byte[] getBootIdentifier() {
return bootIdentifier;
}
public byte[] getBootSystemUse() {
return bootSystemUse;
}
}

View file

@ -1,77 +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.file.formats.iso9660;
/*
* Documentation gathered from http://wiki.osdev.org/ISO_9660
*/
public final class ISO9660Constants {
/*
* Volume Descriptor Type Codes
*/
public final static byte VOLUME_DESC_BOOT_RECORD = 0x0;
public final static byte VOLUME_DESC_PRIMARY_VOLUME_DESC = 0x1;
public final static byte VOLUME_DESC_SUPPL_VOLUME_DESC = 0x2;
public final static byte VOLUME_PARTITION_DESC = 0x3;
public final static byte VOLUME_DESC_SET_TERMINATOR = (byte) 0xff;
/*
* Magic number identifier
*/
public final static String MAGIC_STRING = "CD001";
public final static byte[] MAGIC_BYTES = { 0x43, 0x44, 0x30, 0x30, 0x31 };
public final static int HIDDEN_FILE_FLAG = 0;
public final static int DIRECTORY_FLAG = 1;
public final static int ASSOCIATED_FILE_FLAG = 2;
public final static int EXTENDED_ATTRIBUTE_RECORD_INFO_FLAG = 3;
public final static int OWNER_GROUP_PERMISSIONS_FLAG = 4;
public final static int NOT_FINAL_DIRECTORY_RECORD_FLAG = 5;
public final static Short SECTOR_LENGTH = 0x800;
public final static Byte FILE_STRUCTURE_VERISON = 0x01;
public final static Short APPLICATION_USED_LENGTH = 0x200;
/*
* Lists the three possible address offsets where the ISO9660
* file signature can be located
*/
public final static int SIGNATURE_OFFSET1_0x8001 = 0x8001;
public final static int SIGNATURE_OFFSET2_0x8801 = 0x8801;
public final static int SIGNATURE_OFFSET3_0x9001 = 0x9001;
public final static int MIN_ISO_LENGTH1 = 0x8800;
public final static int MIN_ISO_LENGTH2 = 0x9000;
public final static int MIN_ISO_LENGTH3 = 0x9800;
public final static byte BAD_TYPE = -2;
public final static int UNUSED_SPACER_LEN_32 = 32;
public final static int UNUSED_SPACER_LEN_512 = 512;
public final static int RESERVED_SIZE = 653;
public final static int IDENTIFIER_LENGTH_32 = 32;
public final static int IDENTIFIER_LENGTH_36 = 36;
public final static int IDENTIFIER_LENGTH_37 = 37;
public final static int IDENTIFIER_LENGTH_38 = 38;
public final static int IDENTIFIER_LENGTH_128 = 128;
public final static int BOOT_SYSTEM_USE_LENGTH = 1977;
public final static int DATE_TIME_LENGTH_7 = 7;
public final static int DATE_TIME_LENGTH_17 = 17;
}

View file

@ -1,368 +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.file.formats.iso9660;
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;
private byte extendedAttributeRecordLen;
private int locationOfExtentLE;
private int locationOfExtentBE;
private int dataLengthLE;
private int dataLengthBE;
private byte[] recordingDateTime;
private byte fileFlag;
private byte fileUnitSize;
private byte interleaveGapSize;
private short volumeSequenceNumberLE;
private short volumeSequenceNumberBE;
private byte fileIdentLength;
private byte[] fileIdentifier;
private byte paddingField;
private boolean paddingFieldPresent;
private long volumeIndex;
private String name;
private ISO9660Directory parentDir;
public ISO9660Directory(BinaryReader reader) throws IOException {
this(reader, null);
}
public ISO9660Directory(BinaryReader reader, ISO9660Directory parentDir) throws IOException {
this.parentDir = parentDir;
volumeIndex = reader.getPointerIndex();
directoryRecordLength = reader.readNextByte() & 0xff;
extendedAttributeRecordLen = reader.readNextByte();
locationOfExtentLE = reader.readNextInt();
locationOfExtentBE = readIntBigEndian(reader);
dataLengthLE = reader.readNextInt();
dataLengthBE = readIntBigEndian(reader);
recordingDateTime = reader.readNextByteArray(ISO9660Constants.DATE_TIME_LENGTH_7);
fileFlag = reader.readNextByte();
fileUnitSize = reader.readNextByte();
interleaveGapSize = reader.readNextByte();
volumeSequenceNumberLE = reader.readNextShort();
volumeSequenceNumberBE = readShortBigEndian(reader);
fileIdentLength = reader.readNextByte();
fileIdentifier = reader.readNextByteArray(fileIdentLength);
name = analyzeName(fileIdentifier);
//The padding field will only be present if the
//fileIdentLength is even, otherwise it is not used
if (fileIdentLength % 2 == 0) {
paddingField = reader.readNextByte();
paddingFieldPresent = true;
}
else {
paddingFieldPresent = false;
}
}
private int readIntBigEndian(BinaryReader reader) throws IOException {
setReaderToBigEndian(reader);
int tmp = reader.readNextInt();
setReaderToLittleEndian(reader);
return tmp;
}
private short readShortBigEndian(BinaryReader reader) throws IOException {
setReaderToBigEndian(reader);
short tmp = reader.readNextShort();
setReaderToLittleEndian(reader);
return tmp;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure struc;
struc = new StructureDataType("ISO9600Directory", 0);
struc.add(BYTE, "Directory Record Length", "Length of the Directory Record");
struc.add(BYTE, "Extended Attribute Record Length",
"Length of the Extended Attribute Record");
struc.add(QWORD, "Location of Extent", "LBA in (Little/Big)Endian (4 bytes each)");
struc.add(QWORD, "Data Length", "Size of extent. (Little/Big)Endian (4 bytes each");
struc.add(new ArrayDataType(BYTE, recordingDateTime.length, 1), "Recording date/time",
"Recording date and time");
struc.add(BYTE, "File flags", "File flags");
struc.add(BYTE, "File Unit Size", "File unit size for files recoraded in interleaved mode");
struc.add(BYTE, "Interleave gap size",
"Interleave gap size for files recorded in interleaved mode");
struc.add(DWORD, "Volume Sequence Number", "The clume that this extent is recorded in");
struc.add(BYTE, "File Identifier Length", "Length of the file identifier");
struc.add(new ArrayDataType(BYTE, fileIdentifier.length, 1), "File Identifier",
"File Identifier");
if (paddingFieldPresent) {
struc.add(BYTE, "Padding Field", "Padding Field");
}
return struc;
}
/**
* Creates a string representation of this class filling in field specifics
* when applicable.
* @return the string representation of this class
*/
@Override
public String toString() {
StringBuilder buff = new StringBuilder();
buff.append("Directory Record Length: 0x" + Integer.toHexString(directoryRecordLength) +
"\n");
buff.append("Extended Attribute Record Length: 0x" +
Integer.toHexString(extendedAttributeRecordLen) + "\n");
buff.append("Extent Location: 0x" + Integer.toHexString(getLocationOfExtentLE()) + "\n");
buff.append("Data Length: 0x" + Integer.toHexString(getDataLengthLE()) + "\n");
buff.append("Recording Date/Time: " + createDateTimeString(recordingDateTime) + "\n");
buff.append(getFileFlagString() + "\n");
buff.append("File Unit Size Interleaved Mode: 0x" + Integer.toHexString(fileUnitSize) +
"\n");
buff.append("Interleave Gap Size: 0x" + Integer.toHexString(interleaveGapSize) + "\n");
buff.append("Volume Sequence Number: 0x" +
Integer.toHexString(getVolumeSequenceNumberLE()) + "\n");
buff.append("Length of File Identifier: 0x" + Integer.toHexString(fileIdentLength) + "\n");
buff.append("File Identifier: " + new String(fileIdentifier).trim() + "\n");
if (paddingFieldPresent) {
buff.append("Padding Field: 0x" + Integer.toHexString(paddingField) + "\n");
}
return buff.toString();
}
/*
* Looks at the fileIdentifier and checks if it is made up
* of visible not null ascii characters otherwise returns null
*/
private String analyzeName(byte[] bArr) {
for (int i = 0; i < bArr.length; i++) {
if (bArr[i] < 32) {
return null;
}
}
String tmp = new String(bArr);
return tmp;
}
public boolean isDirectoryFlagSet() {
if (getFlagBit(fileFlag, ISO9660Constants.DIRECTORY_FLAG) == 1) {
return true;
}
return false;
}
ByteProvider getByteProvider(ByteProvider provider, long logicalBlockSize, FSRL fsrl) {
if (!this.isDirectoryFlagSet()) {
long index = locationOfExtentLE * logicalBlockSize;
return new ByteProviderWrapper(provider, index, dataLengthLE, fsrl);
}
return null;
}
/*
* Parses the flag byte to return the string representation
* of the flags bits which are set
*/
private String getFileFlagString() {
String flagString = "";
flagString += "File Flags:\n";
if (getFlagBit(fileFlag, ISO9660Constants.HIDDEN_FILE_FLAG) == 1) {
flagString += "\tHidden File Flag Set";
}
if (getFlagBit(fileFlag, ISO9660Constants.DIRECTORY_FLAG) == 1) {
flagString += "\tDirectory Flag Set";
}
if (getFlagBit(fileFlag, ISO9660Constants.ASSOCIATED_FILE_FLAG) == 1) {
flagString += "\tAssociated File Flag Set";
}
if (getFlagBit(fileFlag, ISO9660Constants.EXTENDED_ATTRIBUTE_RECORD_INFO_FLAG) == 1) {
flagString += "\tExtended Attribute Record Info Flag Set";
}
if (getFlagBit(fileFlag, ISO9660Constants.NOT_FINAL_DIRECTORY_RECORD_FLAG) == 1) {
flagString += "\tNot Final Directory Record Flag";
}
return flagString;
}
private byte getFlagBit(byte flagByte, int flagIndex) {
return (byte) ((flagByte >>> flagIndex) & 1);
}
/**
* Parses the given buffer as an ISO9660 timestamp and returns it as a
* human readable string representation.
*
* Invalid buffers that are still big enough to hold a timestamp are
* still parsed and converted, albeit they are marked as invalid when
* presented to the user.
*
* @param byteArray the buffer to parse (both standard and extended
* formats are handled).
* @return a string with the human readable timestamp.
*/
private String createDateTimeString(byte[] byteArray) {
if (byteArray == null || byteArray.length < 7) {
return "INVALID (truncated or missing)";
}
// Time zone offset from GMT in 15 minute intervals,
// starting at interval -48 (west) and running up to
// interval 52 (east)
int timeOffset = byteArray[byteArray.length - 1];
int i1, i2, i3, i4, i5, i6;
i1 = 1900 + byteArray[0]; // Years since 1900
i2 = byteArray[1]; // Month of year
i3 = byteArray[2]; // Day of month
i4 = byteArray[3]; // Hour of day
i5 = byteArray[4]; // Minute of hour
i6 = byteArray[5]; // Second of minute
// The buffer contains an invalid timezone offset.
boolean validBuffer = true;
if (timeOffset < -48 || timeOffset > 52) {
validBuffer = false;
}
// The buffer contains an invalid date/time.
try {
LocalDateTime.of(i1, i2, i3, i4, i5, i6);
} catch (DateTimeException exception) {
validBuffer = false;
}
StringBuilder builder = new StringBuilder();
if (!validBuffer) {
builder.append("INVALID (");
}
int timezoneIntegral = timeOffset / 4;
int timezoneFractional = (Math.abs(timeOffset) % 4) * 15;
builder.append(String.format("%04d-%02d-%02d %02d:%02d:%02d GMT%c%02d%02d", i1, i2, i3,
i4, i5, i6, timezoneIntegral < 0 ? '-' : '+', timezoneIntegral, timezoneFractional));
if (!validBuffer) {
builder.append(")");
}
return builder.toString();
}
private void setReaderToBigEndian(BinaryReader reader) {
reader.setLittleEndian(false);
}
private void setReaderToLittleEndian(BinaryReader reader) {
reader.setLittleEndian(true);
}
public long getVolumeIndex() {
return volumeIndex;
}
public int getDirectoryRecordLength() {
return directoryRecordLength;
}
public byte getExtendedAttributeRecordLen() {
return extendedAttributeRecordLen;
}
public byte[] getRecordingDateTime() {
return recordingDateTime;
}
public byte getFileFlag() {
return fileFlag;
}
public byte getFileUnitSize() {
return fileUnitSize;
}
public byte getInterleaveGapSize() {
return interleaveGapSize;
}
public int getLocationOfExtentLE() {
return locationOfExtentLE;
}
public int getLocationOfExtentBE() {
return locationOfExtentBE;
}
public int getDataLengthLE() {
return dataLengthLE;
}
public int getDataLengthBE() {
return dataLengthBE;
}
public short getVolumeSequenceNumberLE() {
return volumeSequenceNumberLE;
}
public short getVolumeSequenceNumberBE() {
return volumeSequenceNumberBE;
}
public byte getFileIdentLength() {
return fileIdentLength;
}
public byte[] getFileIdentifier() {
return fileIdentifier;
}
public byte getPaddingField() {
return paddingField;
}
public boolean isPaddingFieldPresent() {
return paddingFieldPresent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ISO9660Directory getParentDirectory() {
return parentDir;
}
public void setParentDirectory(ISO9660Directory parentDir) {
this.parentDir = parentDir;
}
}

View file

@ -15,9 +15,10 @@
*/
package ghidra.file.formats.iso9660;
import java.io.IOException;
import java.util.Arrays;
import java.io.IOException;
import ghidra.app.util.bin.ByteProvider;
import ghidra.formats.gfilesystem.FSRLRoot;
import ghidra.formats.gfilesystem.FileSystemService;
@ -28,6 +29,8 @@ import ghidra.util.task.TaskMonitor;
public class ISO9660FileSystemFactory
implements GFileSystemFactoryByteProvider<ISO9660FileSystem>, GFileSystemProbeByteProvider {
private static final byte[] MAGIC_BYTES = { 0x43, 0x44, 0x30, 0x30, 0x31 }; // "CD001"
private static final long[] SIGNATURE_PROBE_OFFSETS = new long[] { 0x8000L, 0x8800L, 0x9000L };
@Override
@ -43,10 +46,10 @@ public class ISO9660FileSystemFactory
}
private boolean isMagicSignatureAt(ByteProvider provider, long offset) throws IOException {
int magicLen = ISO9660Constants.MAGIC_BYTES.length;
int magicLen = MAGIC_BYTES.length;
long providerLen = provider.length();
return (providerLen > offset + magicLen) &&
Arrays.equals(provider.readBytes(offset, magicLen), ISO9660Constants.MAGIC_BYTES);
Arrays.equals(provider.readBytes(offset, magicLen), MAGIC_BYTES);
}
@Override

View file

@ -1,160 +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.file.formats.iso9660;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
public class ISO9660Header implements StructConverter {
//Hold all volume descriptors
private ArrayList<ISO9660BaseVolume> volumeDescriptorSet;
//HashMaps to hold the LBA index and index size of each path table location
private HashMap<Integer, Short> typeLIndexSizeTable;
private HashMap<Integer, Short> typeMIndexSizeTable;
private HashMap<Integer, Short> supplTypeLIndexSizeTable;
private HashMap<Integer, Short> supplTypeMIndexSizeTable;
//Hold the directory from the primary volume descriptor
//This will be used as a starting point to recurse though the directory tree structure
//inside of the analyzer
private ISO9660Directory directory;
private ISO9660VolumeDescriptor primaryDesc;
private byte type;
public ISO9660Header(BinaryReader reader) throws IOException {
volumeDescriptorSet = new ArrayList<ISO9660BaseVolume>();
typeLIndexSizeTable = new HashMap<Integer, Short>();
typeMIndexSizeTable = new HashMap<Integer, Short>();
supplTypeLIndexSizeTable = new HashMap<Integer, Short>();
supplTypeMIndexSizeTable = new HashMap<Integer, Short>();
type = ISO9660Constants.BAD_TYPE; //Bad type to fall into loop
while (type != ISO9660Constants.VOLUME_DESC_SET_TERMINATOR) {
// not terminator set
type = reader.readNextByte();
reader.setPointerIndex(reader.getPointerIndex() - 1);
if (type == ISO9660Constants.VOLUME_DESC_BOOT_RECORD) {
volumeDescriptorSet.add(new ISO9660BootRecordVolumeDescriptor(reader));
}
else if (type == ISO9660Constants.VOLUME_DESC_PRIMARY_VOLUME_DESC) {
primaryDesc = new ISO9660VolumeDescriptor(reader);
directory = primaryDesc.getDirectoryEntry();
volumeDescriptorSet.add(primaryDesc);
typeLIndexSizeTable.put(primaryDesc.getTypeLPathTableLocation(),
primaryDesc.getLogicalBlockSizeLE());
typeMIndexSizeTable.put(primaryDesc.getTypeMPathTableLocation(),
primaryDesc.getLogicalBlockSizeBE());
if (primaryDesc.getDirectoryEntry().isPaddingFieldPresent()) {
reader.setPointerIndex(reader.getPointerIndex() - 1);
}
}
else if (type == ISO9660Constants.VOLUME_DESC_SUPPL_VOLUME_DESC) {
ISO9660VolumeDescriptor supplDesc = new ISO9660VolumeDescriptor(reader);
volumeDescriptorSet.add(supplDesc);
supplTypeLIndexSizeTable.put(supplDesc.getTypeLPathTableLocation(),
supplDesc.getLogicalBlockSizeLE());
supplTypeMIndexSizeTable.put(supplDesc.getTypeMPathTableLocation(),
supplDesc.getLogicalBlockSizeBE());
if (supplDesc.getDirectoryEntry().isPaddingFieldPresent()) {
reader.setPointerIndex(reader.getPointerIndex() - 1);
}
}
}
// got terminator set
volumeDescriptorSet.add(new ISO9660SetTerminator(reader));
}
public ISO9660Directory getPrimaryDirectory() {
return directory;
}
public ArrayList<ISO9660BaseVolume> getVolumeDescriptorSet() {
return volumeDescriptorSet;
}
public HashMap<Integer, Short> getTypeLIndexSizeTable() {
return typeLIndexSizeTable;
}
public HashMap<Integer, Short> getTypeMIndexSizeTable() {
return typeMIndexSizeTable;
}
public HashMap<Integer, Short> getSupplTypeLIndexSizeTable() {
return supplTypeLIndexSizeTable;
}
public HashMap<Integer, Short> getSupplTypeMIndexSizeTable() {
return supplTypeMIndexSizeTable;
}
public ISO9660VolumeDescriptor getPrimaryVolumeDescriptor() {
return primaryDesc;
}
/**
* Creates a string representation of this class filling in field specifics
* when applicable.
* @return the string representation of this class
*/
@Override
public String toString() {
StringBuffer buff = new StringBuffer();
for (ISO9660BaseVolume volume : volumeDescriptorSet) {
buff.append(volume.toString());
}
return buff.toString();
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure struc = new StructureDataType("ISO9660Header", 0);
DataType data;
for (ISO9660BaseVolume volume : volumeDescriptorSet) {
data = volume.toDataType();
struc.add(data);
}
return struc;
}
}

View file

@ -1,140 +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.file.formats.iso9660;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
public class ISO9660PathTable implements StructConverter {
private byte dirIdentifierLength;
private byte extendedAttributeRecordLength;
private int locationOfExtent;
private short directoryNumberPathIndex;
private byte[] directoryIdentifier;
private byte paddingField;
private boolean paddingFieldPresent;
private long volumeIndex;
private boolean littleEndian;
public ISO9660PathTable(BinaryReader reader, boolean littleEndian) throws IOException {
reader.setLittleEndian(littleEndian);
this.littleEndian = littleEndian;
volumeIndex = reader.getPointerIndex();
dirIdentifierLength = reader.readNextByte();
extendedAttributeRecordLength = reader.readNextByte();
locationOfExtent = reader.readNextInt();
directoryNumberPathIndex = reader.readNextShort();
directoryIdentifier = reader.readNextByteArray(dirIdentifierLength);
//The padding field is only present if the directoryIdentifierLength
//is odd, otherwise it is not used.
if (dirIdentifierLength % 2 != 0) {
paddingField = reader.readNextByte();
paddingFieldPresent = true;
}
else {
paddingFieldPresent = false;
}
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure struc;
if (littleEndian) {
struc = new StructureDataType("ISO9660TypeLPathTable", 0);
}
else {
struc = new StructureDataType("ISO9660TypeMPathTable", 0);
}
struc.add(BYTE, "Directory Identifier Length", "Length of Directory Identifier");
struc.add(BYTE, "Extended Attribute Record Length", "Length of Extended Attribute Record");
struc.add(DWORD, "Location of Extent", "Location of Extent in Little-endian format");
struc.add(WORD, "Directory Number",
"Number of parent directory (an index in to the path table)");
struc.add(new ArrayDataType(BYTE, directoryIdentifier.length, 1), "Directory Identifier",
"Directory Identifier");
if (paddingFieldPresent) {
struc.add(BYTE, "Padding Field", "Padding Field");
}
return struc;
}
/**
* Creates a string representation of this class filling in field specifics
* when applicable.
* @return the string representation of this class
*/
@Override
public String toString() {
StringBuffer buff = new StringBuffer();
buff.append("Directory Identifier Length: 0x" + Integer.toHexString(dirIdentifierLength) +
"\n");
buff.append("Extended Attribute Record Length: " +
Integer.toHexString(extendedAttributeRecordLength) + "\n");
buff.append("Location of Extent (LBA): 0x" + Integer.toHexString(locationOfExtent) + "\n");
buff.append("Directory Number: 0x" + Integer.toHexString(directoryNumberPathIndex) + "\n");
buff.append("Directory Identifier: " + new String(directoryIdentifier).trim() + "\n");
if (paddingFieldPresent) {
buff.append("PaddingF ield: 0x" + Integer.toHexString(paddingField) + "\n");
}
return buff.toString();
}
public byte getDirIdentifierLength() {
return dirIdentifierLength;
}
public byte getExtendedAttributeRecordLength() {
return extendedAttributeRecordLength;
}
public int getLocationOfExtent() {
return locationOfExtent;
}
public short getDirectoryNumberPathIndex() {
return directoryNumberPathIndex;
}
public byte[] getDirectoryIdentifier() {
return directoryIdentifier;
}
public byte getPaddingField() {
return paddingField;
}
public boolean isPaddingFieldPresent() {
return paddingFieldPresent;
}
public long getVolumeIndex() {
return volumeIndex;
}
public boolean isLittleEndian() {
return littleEndian;
}
}

View file

@ -1,54 +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.file.formats.iso9660;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* The terminator flag to note the end of the set of volume descriptors
* on this ISO
*/
public class ISO9660SetTerminator extends ISO9660BaseVolume {
private long endVolumeIndex;
public ISO9660SetTerminator(BinaryReader reader) throws IOException {
super(reader);
endVolumeIndex = reader.getPointerIndex();
}
public long getEndVolumeIndex() {
return endVolumeIndex;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure struc = new StructureDataType("ISO9600SetTerminator", 0);
struc.add(BYTE, "Type", "Volume Descriptor Type");
struc.add(new ArrayDataType(BYTE, super.getIdentifier().length, 1), "Identifier",
"Identifier");
struc.add(BYTE, "Version", "Volume Descriptor Version");
return struc;
}
}

View file

@ -1,489 +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.file.formats.iso9660;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import java.time.DateTimeException;
import java.time.LocalDateTime;
public class ISO9660VolumeDescriptor extends ISO9660BaseVolume {
private byte unused; // Always 0x00
private byte[] systemIdentifier; // Length 0x20
private byte[] volumeIdentifier; // Length 0x20
private long unused2; // All 0x00
private int volumeSpaceSizeLE; // Little-endian
private int volumeSpaceSizeBE; // Big-endian
private byte[] unused3; // Length 0x20
private short volumeSetSizeLE; // Little-endian
private short volumeSetSizeBE; // Big-endian
private short volumeSeqNumberLE; // Little-endian
private short volumeSeqNumberBE; // Big-endian
private short logicalBlockSizeLE; // Little-endian
private short logicalBlockSizeBE; // Big-endian
private int pathTableSizeLE; // Litte-endian
private int pathTableSizeBE; // Big-endian
private int typeLPathTableLocation; // -int32_LSB-
private int optionalTypeLPathTableLocation; // -int32_LSB-
private int typeMPathTableLocation; // -int32_MSB-
private int optionalTypeMPathTableLocation; // -int32_MSB-
private ISO9660Directory directoryEntry; // Length 0x20
private byte[] volumeSetIdentifier; // Length 0x80
private byte[] publisherIdentifier; // Length 0x80
private byte[] dataPreparerIdentifier; // Length 0x80
private byte[] applicationIdentifier; // Length 0x80
private byte[] copyrightFileIdentifier; // Length 0x26
private byte[] abstractFileIdentifier; // Length 0x24
private byte[] bibliographicFileIdentifier; // Length 0x25
private byte[] volumeCreationDateTime; // Length 0x11
private byte[] volumeModifyDateTime; // Length 0x11
private byte[] volumeExpirationDateTime; // Length 0x11
private byte[] volumeEffectiveDateTime; // length 0x11
private byte fileStructureVersion; // -int8-
private byte unused4; // Always 0x00
private byte[] applicationUsed; // Length 0x200
private byte[] reserved; // Length 0x28D
public ISO9660VolumeDescriptor(BinaryReader reader) throws IOException {
super(reader);
unused = reader.readNextByte();
systemIdentifier = reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_32);
volumeIdentifier = reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_32);
unused2 = reader.readNextLong();
volumeSpaceSizeLE = reader.readNextInt();
volumeSpaceSizeBE = readIntBigEndian(reader);
unused3 = reader.readNextByteArray(ISO9660Constants.UNUSED_SPACER_LEN_32);
volumeSetSizeLE = reader.readNextShort();
volumeSetSizeBE = readShortBigEndian(reader);
volumeSeqNumberLE = reader.readNextShort();
volumeSeqNumberBE = readShortBigEndian(reader);
logicalBlockSizeLE = reader.readNextShort();
logicalBlockSizeBE = readShortBigEndian(reader);
pathTableSizeLE = reader.readNextInt();
pathTableSizeBE = readIntBigEndian(reader);
typeLPathTableLocation = reader.readNextInt();
optionalTypeLPathTableLocation = reader.readNextInt();
typeMPathTableLocation = readIntBigEndian(reader);
optionalTypeMPathTableLocation = readIntBigEndian(reader);
directoryEntry = new ISO9660Directory(reader);
volumeSetIdentifier = reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_128);
publisherIdentifier = reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_128);
dataPreparerIdentifier = reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_128);
applicationIdentifier = reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_128);
copyrightFileIdentifier = reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_38);
abstractFileIdentifier = reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_36);
bibliographicFileIdentifier =
reader.readNextByteArray(ISO9660Constants.IDENTIFIER_LENGTH_37);
volumeCreationDateTime = reader.readNextByteArray(ISO9660Constants.DATE_TIME_LENGTH_17);
volumeModifyDateTime = reader.readNextByteArray(ISO9660Constants.DATE_TIME_LENGTH_17);
volumeExpirationDateTime = reader.readNextByteArray(ISO9660Constants.DATE_TIME_LENGTH_17);
volumeEffectiveDateTime = reader.readNextByteArray(ISO9660Constants.DATE_TIME_LENGTH_17);
fileStructureVersion = reader.readNextByte();
unused4 = reader.readNextByte();
applicationUsed = reader.readNextByteArray(ISO9660Constants.UNUSED_SPACER_LEN_512);
reserved = reader.readNextByteArray(ISO9660Constants.RESERVED_SIZE);
}
private int readIntBigEndian(BinaryReader reader) throws IOException {
setReaderToBigEndian(reader);
int tmp = reader.readNextInt();
setReaderToLittleEndian(reader);
return tmp;
}
private short readShortBigEndian(BinaryReader reader) throws IOException {
setReaderToBigEndian(reader);
short tmp = reader.readNextShort();
setReaderToLittleEndian(reader);
return tmp;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure struc;
if (super.getTypeCode() == ISO9660Constants.VOLUME_DESC_PRIMARY_VOLUME_DESC) {
struc = new StructureDataType("ISO9600PrimaryVolumeDescriptor", 0);
}
else if (super.getTypeCode() == ISO9660Constants.VOLUME_DESC_SUPPL_VOLUME_DESC) {
struc = new StructureDataType("ISO9600SupplementaryVolumeDescriptor", 0);
}
else {
struc = null;
}
struc.add(BYTE, "Type Code", "Type of volume descriptor");
struc.add(new ArrayDataType(BYTE, super.getIdentifier().length, 1), "Standard Identifier",
"Always 'CD001'");
struc.add(BYTE, "Version", "Always 0x01");
struc.add(BYTE, "Unused", "Always 0x00");
struc.add(new ArrayDataType(BYTE, systemIdentifier.length, 1), "System Identifier",
"Name of the system to act upon sectors 0x00-0x0F");
struc.add(new ArrayDataType(BYTE, volumeIdentifier.length, 1), "Volume Identifier",
"Identification for this volume");
struc.add(QWORD, "Unused", "Always 0x00");
struc.add(QWORD, "Volume Space Size", "Number of logical blocks the volume is recorded");
struc.add(new ArrayDataType(BYTE, unused3.length, 1), "Unused", "Always 0x00");
struc.add(DWORD, "Volume Set Size", "Size of the set in this logical volume");
struc.add(DWORD, "Volume Sequence Number", "Number of disks in volume set");
struc.add(DWORD, "Logical block Size", "Size of the logical block");
struc.add(QWORD, "Path Table Size", "Size of the path table");
struc.add(DWORD, "Location of Type-L Path Dable",
"LBA location of the path table containing only litle-endian values");
struc.add(DWORD, "Location of Optional Type-L Path Table",
"LBA location of the optional path table containing only little-endian values");
struc.add(DWORD, "Location of Type-M Path Table",
"LBA location of the path table containing only big-endian values");
struc.add(DWORD, "Location of Optional Type-M Path Table",
"LBA location of the optional path table containing only big-endian values");
struc.add(directoryEntry.toDataType());
struc.add(new ArrayDataType(BYTE, volumeSetIdentifier.length, 1), "Volume Set Identifier",
"Identifier of the volume set which this volume is a member");
struc.add(new ArrayDataType(BYTE, publisherIdentifier.length, 1), "Publisher Identifier",
"The volume publisher");
struc.add(new ArrayDataType(BYTE, dataPreparerIdentifier.length, 1),
"Data Preparer Identifier", "Identifier of person(s) who prepared data for this volume");
struc.add(new ArrayDataType(BYTE, applicationIdentifier.length, 1),
"Application Identifier", "How the data are recorded on this volume");
struc.add(new ArrayDataType(BYTE, copyrightFileIdentifier.length, 1),
"Copyright File Identifier",
"Filename of file that contains copyright information on volume set");
struc.add(new ArrayDataType(BYTE, abstractFileIdentifier.length, 1),
"Abstract File Identifier",
"Filename of file that contains abstract information on volume set");
struc.add(new ArrayDataType(BYTE, bibliographicFileIdentifier.length, 1),
"Bibliographic File Identifier",
"Filename of file that contians bibliographic information on volume set");
struc.add(new ArrayDataType(BYTE, volumeCreationDateTime.length, 1),
"Volume Creation Date and Time", "Date and time volume was created");
struc.add(new ArrayDataType(BYTE, volumeModifyDateTime.length, 1),
"Volume Modification Date and Time", "Date and time volume was modified");
struc.add(new ArrayDataType(BYTE, volumeExpirationDateTime.length, 1),
"Volume Expiration Date and Time", "Date and time volume was created");
struc.add(new ArrayDataType(BYTE, volumeEffectiveDateTime.length, 1),
"Volume Effective Date and Time", "Date and time after which the volume may be used");
struc.add(BYTE, "File Structure Version", "Directory records and path table version");
struc.add(BYTE, "Unused", "Always 0x00");
struc.add(new ArrayDataType(BYTE, applicationUsed.length, 1), "Application Used",
"Contents not defined by ISO 9660");
struc.add(new ArrayDataType(BYTE, reserved.length, 1), "Reserved", "Reserved by ISO");
return struc;
}
@Override
public String toString() {
StringBuilder buff = new StringBuilder();
buff.append("Type Code: 0x" + Integer.toHexString(super.getTypeCode()) + " => " +
getTypeCodeString() + "\n");
buff.append("Standard Identifier: " + new String(super.getIdentifier()).trim() + "\n");
buff.append("Version: 0x" + Integer.toHexString(super.getVersion()) + "\n");
buff.append("Unused: 0x" + Integer.toHexString(unused) + "\n");
buff.append("System Identifier: " + new String(systemIdentifier).trim() + "\n");
buff.append("Volume Identifier: " + new String(volumeIdentifier).trim() + "\n");
buff.append("Unused Field: 0x" + Long.toHexString(unused2) + "\n");
buff.append("Volume Space Size: 0x" + Integer.toHexString(getVolumeSpaceSizeLE()) + "\n");
buff.append("Unused: " + new String(unused3).trim() + "\n");
buff.append("Volume Set Size: 0x" + Integer.toHexString(getVolumeSetSizeLE()) + "\n");
buff.append("Volume Sequence Number: 0x" + Integer.toHexString(getVolumeSeqNumberLE()) +
"\n");
buff.append("Logical Block Size: 0x" + Integer.toHexString(getLogicalBlockSizeLE()) + "\n");
buff.append("Path Table Size: 0x" + Integer.toHexString(getPathTableSizeLE()) + "\n");
buff.append("LBA Location of Type-L Path Table: 0x" +
Integer.toHexString(typeLPathTableLocation) + "\n");
buff.append("LBA Location of Optional Type-L Path Table: 0x" +
Integer.toHexString(optionalTypeLPathTableLocation) + "\n");
buff.append("LBA Location of Type-M Path Table: 0x" +
Integer.toHexString(typeMPathTableLocation) + "\n");
buff.append("LBA Location of Optional Type-M Path Table: 0x" +
Integer.toHexString(optionalTypeMPathTableLocation) + "\n");
buff.append("Calculated Location of Type-L Path Table: 0x" +
Integer.toHexString(typeLPathTableLocation * getLogicalBlockSizeLE()) + "\n");
buff.append("Calculated Location of Type-M Path Table: 0x" +
Integer.toHexString(typeMPathTableLocation * getLogicalBlockSizeBE()) + "\n");
buff.append("Directory Entry for Root Directory: \n" + directoryEntry.toString() + "\n");
buff.append("Volume Set Identifier: " + new String(volumeSetIdentifier).trim() + "\n");
buff.append("Publisher Identifier: " + new String(publisherIdentifier).trim() + "\n");
buff.append("Data Preparer Identifier: " + new String(dataPreparerIdentifier).trim() + "\n");
buff.append("Application Identifier: " + new String(applicationIdentifier).trim() + "\n");
buff.append("Copyright File Identifier: " + new String(copyrightFileIdentifier).trim() +
"\n");
buff.append("Abstract File Identifier: " + new String(abstractFileIdentifier).trim() + "\n");
buff.append("Biliographic File Identifier: " + new String(bibliographicFileIdentifier) +
"\n");
buff.append("Volume Creation Date/Time: " + createDateTimeString(volumeCreationDateTime) +
"\n");
buff.append("Volume Modification Date/Time: " + createDateTimeString(volumeModifyDateTime) +
"\n");
buff.append("Volume Expiration Date/Time: " + createDateTimeString(volumeCreationDateTime) +
"\n");
buff.append("Volume Effective Date/Time: " + createDateTimeString(volumeEffectiveDateTime) +
"\n");
buff.append("File Structure Version: 0x" + Integer.toHexString(fileStructureVersion) + "\n");
buff.append("Unused: 0x" + Integer.toHexString(unused4) + "\n");
return buff.toString();
}
/**
* Checks whether the given string is entirely made up of ASCII digits.
*
* @param string the string to check.
* @return true if all characters in the string are ASCII digits, false
* otherwise.
*/
private boolean isDigitsStringValid(String string) {
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
if (c < '0' || c > '9') {
return false;
}
}
return true;
}
/**
* Parses the given buffer as an ISO9660 timestamp and returns it as a
* human readable string representation.
*
* Invalid buffers that are still big enough to hold a timestamp are
* still parsed and converted, albeit they are marked as invalid when
* presented to the user.
*
* @param byteArray the buffer to parse (only extended timestamp format
* is handled).
* @return a string with the human readable timestamp.
*/
protected String createDateTimeString(byte[] byteArray) {
if (byteArray == null || byteArray.length < 17) {
return "INVALID (truncated or missing)";
}
String s1, s2, s3, s4, s5, s6, s7;
// Time zone offset from GMT in 15 minute intervals,
// starting at interval -48 (west) and running up to
// interval 52 (east)
int timeOffset = byteArray[byteArray.length - 1];
String bString = new String(byteArray);
s1 = bString.substring(0, 4); //year 1 to 9999
s2 = bString.substring(4, 6); //month 1 to 12
s3 = bString.substring(6, 8); //day 1 to 31
s4 = bString.substring(8, 10); //hour 0 to 23
s5 = bString.substring(10, 12); //minute 0 to 59
s6 = bString.substring(12, 14); //second 0 to 59
s7 = bString.substring(14, 16); //ms 0 to 99
// Validate strings first.
boolean validBuffer = isDigitsStringValid(s1) && isDigitsStringValid(s2) && isDigitsStringValid(s3) &&
isDigitsStringValid(s4) && isDigitsStringValid(s5) && isDigitsStringValid(s6) && isDigitsStringValid(s7);
try {
// The buffer contains an invalid date/time.
LocalDateTime.of(Integer.parseInt(s1), Integer.parseInt(s2), Integer.parseInt(s3),
Integer.parseInt(s4), Integer.parseInt(s5), Integer.parseInt(s6));
} catch (NumberFormatException | DateTimeException e) {
validBuffer = false;
}
// The buffer contains an invalid timezone offset.
if (timeOffset < -48 || timeOffset > 52) {
validBuffer = false;
}
/*
* Time zone offset from GMT in 15 minute intervals,
* starting at interval -48 (west) and running up to
* interval 52 (east).
*/
int timezoneIntegral = timeOffset / 4;
int timezoneFractional = (Math.abs(timeOffset) % 4) * 15;
StringBuilder builder = new StringBuilder();
if (!validBuffer) {
builder.append("INVALID(");
}
builder.append(String.format("%s-%s-%s %s:%s:%s.%s GMT%c%02d%02d", s1, s2, s3, s4, s5, s6, s7,
timezoneIntegral < 0 ? '-' : '+', timezoneIntegral, timezoneFractional));
if (!validBuffer) {
builder.append(")");
}
return builder.toString();
}
public byte getUnused() {
return unused;
}
public byte[] getSystemIdentifier() {
return systemIdentifier;
}
public byte[] getVolumeIdentifier() {
return volumeIdentifier;
}
public long getUnused2() {
return unused2;
}
public byte[] getUnused3() {
return unused3;
}
public int getVolumeSpaceSizeLE() {
return volumeSpaceSizeLE;
}
public int getVolumeSpaceSizeBE() {
return volumeSpaceSizeBE;
}
public short getVolumeSetSizeLE() {
return volumeSetSizeLE;
}
public short getVolumeSetSizeBE() {
return volumeSetSizeBE;
}
public short getVolumeSeqNumberLE() {
return volumeSeqNumberLE;
}
public short getVolumeSeqNumberBE() {
return volumeSeqNumberBE;
}
public short getLogicalBlockSizeLE() {
return logicalBlockSizeLE;
}
public short getLogicalBlockSizeBE() {
return logicalBlockSizeBE;
}
public int getPathTableSizeLE() {
return pathTableSizeLE;
}
public int getPathTableSizeBE() {
return pathTableSizeBE;
}
public int getTypeLPathTableLocation() {
return typeLPathTableLocation;
}
public int getOptionalTypeLPathTableLocation() {
return optionalTypeLPathTableLocation;
}
public int getTypeMPathTableLocation() {
return typeMPathTableLocation;
}
public int getOptionalTypeMPathTableLocation() {
return optionalTypeMPathTableLocation;
}
public ISO9660Directory getDirectoryEntry() {
return directoryEntry;
}
public byte[] getVolumeSetIdentifier() {
return volumeSetIdentifier;
}
public byte[] getPublisherIdentifier() {
return publisherIdentifier;
}
public byte[] getDataPreparerIdentifier() {
return dataPreparerIdentifier;
}
public byte[] getApplicationIdentifier() {
return applicationIdentifier;
}
public byte[] getCopyrightFileIdentifier() {
return copyrightFileIdentifier;
}
public byte[] getAbstractFileIdentifier() {
return abstractFileIdentifier;
}
public byte[] getBibliographicFileIdentifier() {
return bibliographicFileIdentifier;
}
public byte[] getVolumeCreationDateTime() {
return volumeCreationDateTime;
}
public byte[] getVolumeModifyDateTime() {
return volumeModifyDateTime;
}
public byte[] getVolumeExpirationDateTime() {
return volumeExpirationDateTime;
}
public byte[] getVolumeEffectiveDateTime() {
return volumeEffectiveDateTime;
}
public byte getFileStructureVersion() {
return fileStructureVersion;
}
public byte getUnused4() {
return unused4;
}
public byte[] getApplicationUsed() {
return applicationUsed;
}
public byte[] getReserved() {
return reserved;
}
private void setReaderToBigEndian(BinaryReader reader) {
reader.setLittleEndian(false);
}
private void setReaderToLittleEndian(BinaryReader reader) {
reader.setLittleEndian(true);
}
}

View file

@ -43,8 +43,7 @@ public class LzssAnalyzer extends FileFormatAnalyzer implements AnalysisWorker {
throws Exception, CancelledException {
Address address = program.getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
LzssCompressionHeader header = new LzssCompressionHeader(provider);
if (header.getSignature() != LzssConstants.SIGNATURE_COMPRESSION) {
@ -72,22 +71,27 @@ public class LzssAnalyzer extends FileFormatAnalyzer implements AnalysisWorker {
return getName();
}
@Override
public boolean canAnalyze(Program program) {
return LzssUtil.isLZSS(program);
}
@Override
public boolean getDefaultEnablement(Program program) {
return LzssUtil.isLZSS(program);
}
@Override
public String getDescription() {
return "Annotates an LZSS compression file.";
}
@Override
public String getName() {
return "LZSS Compression Annotation";
}
@Override
public boolean isPrototype() {
return true;
}

View file

@ -15,17 +15,17 @@
*/
package ghidra.file.formats.xar;
import java.util.Arrays;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.program.model.listing.Program;
import java.util.Arrays;
public class XARUtil {
public final static boolean isXAR( Program program ) {
ByteProvider provider = new MemoryByteProvider( program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace() );
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, true);
return isXAR( provider );
}

View file

@ -81,7 +81,7 @@ public class YAFFS2Analyzer extends FileFormatAnalyzer implements AnalysisWorker
Address address = program.getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, true);
int index = 0;

View file

@ -34,8 +34,8 @@ public class PEUtil {
return true;
}
if (format.equals(BinaryLoader.BINARY_NAME)) {
MemoryByteProvider mbp = new MemoryByteProvider(program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace());
MemoryByteProvider mbp =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
try {
BinaryReader reader = new BinaryReader(mbp, true/*LittleEndian*/);
DOSHeader dosHeader = new DOSHeader(reader);

View file

@ -15,10 +15,11 @@
*/
package ghidra.javaclass.analyzers;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.services.AnalysisPriority;
@ -97,8 +98,7 @@ public class JvmSwitchAnalyzer extends AbstractJavaAnalyzer {
monitor.setMaximum(set.getNumAddresses());
monitor.setProgress(0);
ByteProvider provider =
new MemoryByteProvider(program.getMemory(), program.getMinAddress());
ByteProvider provider = MemoryByteProvider.createProgramHeaderByteProvider(program, false);
BinaryReader reader = new BinaryReader(provider, false);
Listing listing = program.getListing();