Merge remote-tracking branch 'origin/GP-51_ryanmkurtz_coff-check'

This commit is contained in:
Ryan Kurtz 2022-12-20 13:26:20 -05:00
commit 25a70bb719
3 changed files with 59 additions and 43 deletions

View file

@ -30,7 +30,6 @@ import ghidra.program.flatapi.FlatProgramAPI;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.Memory;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.NotEmptyException;
import ghidra.util.task.TaskMonitor;
@ -52,10 +51,10 @@ public class CoffBinaryAnalysisCommand extends FlatProgramAPI
if (!BinaryLoader.BINARY_NAME.equals(format)) {
return false;
}
Memory memory = program.getMemory();
short magic =
memory.getShort(program.getAddressFactory().getDefaultAddressSpace().getAddress(0));
return CoffMachineType.isMachineTypeDefined(magic);
ByteProvider provider =
MemoryByteProvider.createDefaultAddressSpaceByteProvider(program, false);
return CoffFileHeader.isValid(provider);
}
catch (Exception e) {
return false;

View file

@ -56,7 +56,7 @@ public class CoffFileHeader implements StructConverter {
}
}
private BinaryReader getBinaryReader(ByteProvider provider) {
private static BinaryReader getBinaryReader(ByteProvider provider) {
BinaryReader reader = new BinaryReader(provider, true/*COFF is always LE!!!*/);
return reader;
}
@ -271,6 +271,46 @@ public class CoffFileHeader implements StructConverter {
return _aoutHeader;
}
/**
* Tests if the given {@link ByteProvider} is a valid {@link CoffFileHeader}.
* <p>
* To avoid false positives when the machine type is
* {@link CoffMachineType#IMAGE_FILE_MACHINE_UNKNOWN}, we do an additional check on some extra
* bytes at the beginning of the given {@link ByteProvider} to make sure the entire file isn't
* all 0's.
*
* @param provider The {@link ByteProvider} to check
* @return True if this is a is a valid {@link CoffFileHeader}; otherwise, false
* @throws IOException if there was an IO-related issue
*/
public static boolean isValid(ByteProvider provider) throws IOException {
final int MIN_BYTE_LENGTH = 22;
final int COFF_NULL_SANITY_CHECK_LEN = 64;
if (provider.length() < MIN_BYTE_LENGTH) {
return false;
}
short magic = getBinaryReader(provider).readShort(0);
if (magic == CoffMachineType.IMAGE_FILE_MACHINE_UNKNOWN /* ie. == 0 */ &&
provider.length() > COFF_NULL_SANITY_CHECK_LEN) {
byte[] headerBytes = provider.readBytes(0, COFF_NULL_SANITY_CHECK_LEN);
boolean allZeros = true;
for (byte b : headerBytes) {
allZeros = (b == 0);
if (!allZeros) {
break;
}
}
if (allZeros) {
return false;
}
}
return CoffMachineType.isMachineTypeDefined(magic);
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure struct = new StructureDataType(StructConverterUtil.parseName(getClass()), 0);

View file

@ -46,15 +46,12 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
public final static String COFF_NAME = "Common Object File Format (COFF)";
public static final String FAKE_LINK_OPTION_NAME = "Attempt to link sections located at 0x0";
static final boolean FAKE_LINK_OPTION_DEFAULT = true;
private static final int COFF_NULL_SANITY_CHECK_LEN = 64;
// where do sections start if they're all zero??? this affects object files
// and if we're high enough (!!!) the scalar operand analyzer will work
// properly with external symbols laid down
private static final int EMPTY_START_OFFSET = 0x2000;
private static final long MIN_BYTE_LENGTH = 22;
/**
* @return true if this loader assumes the Microsoft variant of the COFF format
*/
@ -97,47 +94,27 @@ public class CoffLoader extends AbstractLibrarySupportLoader {
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
List<LoadSpec> loadSpecs = new ArrayList<>();
if (provider.length() < MIN_BYTE_LENGTH) {
if (!CoffFileHeader.isValid(provider)) {
return loadSpecs;
}
CoffFileHeader header = new CoffFileHeader(provider);
header.parseSectionHeaders(provider);
// Check to prevent false positives when the file is full of '\0' bytes.
// If the machine type is unknown (0), check the first 64 bytes of the file and bail if
// they are also all 0.
if (header.getMagic() == CoffMachineType.IMAGE_FILE_MACHINE_UNKNOWN /* ie. == 0 */ &&
provider.length() > COFF_NULL_SANITY_CHECK_LEN) {
byte[] headerBytes = provider.readBytes(0, COFF_NULL_SANITY_CHECK_LEN);
boolean allZeros = true;
for (byte b : headerBytes) {
allZeros = (b == 0);
if (!allZeros) {
break;
}
}
if (allZeros) {
return loadSpecs;
}
if (isVisualStudio(header) != isMicrosoftFormat()) {
// Only one of the CoffLoader/MSCoffLoader will survive this check
return loadSpecs;
}
String secondary = isCLI(header) ? "cli" : Integer.toString(header.getFlags() & 0xffff);
List<QueryResult> results =
QueryOpinionService.query(getName(), header.getMachineName(), secondary);
for (QueryResult result : results) {
loadSpecs.add(new LoadSpec(this, header.getImageBase(isMicrosoftFormat()), result));
}
if (loadSpecs.isEmpty()) {
loadSpecs.add(new LoadSpec(this, header.getImageBase(false), true));
}
if (CoffMachineType.isMachineTypeDefined(header.getMagic())) {
header.parseSectionHeaders(provider);
if (isVisualStudio(header) != isMicrosoftFormat()) {
// Only one of the CoffLoader/MSCoffLoader will survive this check
return loadSpecs;
}
String secondary = isCLI(header) ? "cli" : Integer.toString(header.getFlags() & 0xffff);
List<QueryResult> results =
QueryOpinionService.query(getName(), header.getMachineName(), secondary);
for (QueryResult result : results) {
loadSpecs.add(new LoadSpec(this, header.getImageBase(isMicrosoftFormat()), result));
}
if (loadSpecs.isEmpty()) {
loadSpecs.add(new LoadSpec(this, header.getImageBase(false), true));
}
}
return loadSpecs;
}