GP-64 Partial Clang-for-Win support: PeLoader, opinion/ldefs, fix some

analyzers and their helpers and tests
This commit is contained in:
ghizard
2020-08-07 11:11:29 -04:00
parent 4506acddf9
commit 0013025a40
8 changed files with 54 additions and 49 deletions
@@ -182,7 +182,8 @@ public class PeLoader extends AbstractPeDebugLoader {
} }
@Override @Override
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) { public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
Program program) {
if (options != null) { if (options != null) {
for (Option option : options) { for (Option option : options) {
String name = option.getName(); String name = option.getName();
@@ -797,16 +798,20 @@ public class PeLoader extends AbstractPeDebugLoader {
"This program must be run under Win32\r\n$".toCharArray(); "This program must be run under Win32\r\n$".toCharArray();
static final char[] errString_GCC_VS = static final char[] errString_GCC_VS =
"This program cannot be run in DOS mode.\r\r\n$".toCharArray(); "This program cannot be run in DOS mode.\r\r\n$".toCharArray();
static final char[] errString_Clang =
"This program cannot be run in DOS mode.$".toCharArray();
static final int[] asm16_Borland = { 0xBA, 0x10, 0x00, 0x0E, 0x1F, 0xB4, 0x09, 0xCD, 0x21, static final int[] asm16_Borland = { 0xBA, 0x10, 0x00, 0x0E, 0x1F, 0xB4, 0x09, 0xCD, 0x21,
0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x90, 0x90 }; 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x90, 0x90 };
static final int[] asm16_GCC_VS = static final int[] asm16_GCC_VS_Clang =
{ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21 }; { 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21 };
public enum CompilerEnum { public enum CompilerEnum {
VisualStudio("visualstudio:unknown"), VisualStudio("visualstudio:unknown"),
GCC("gcc:unknown"), GCC("gcc:unknown"),
Clang("clang:unknown"),
GCC_VS("visualstudiogcc"), GCC_VS("visualstudiogcc"),
GCC_VS_Clang("visualstudiogccclang"),
BorlandPascal("borland:pascal"), BorlandPascal("borland:pascal"),
BorlandCpp("borland:c++"), BorlandCpp("borland:c++"),
BorlandUnk("borland:unknown"), BorlandUnk("borland:unknown"),
@@ -892,7 +897,11 @@ public class PeLoader extends AbstractPeDebugLoader {
if (dh.e_lfanew() == 0x80) { if (dh.e_lfanew() == 0x80) {
offsetChoice = CompilerEnum.GCC_VS; offsetChoice = CompilerEnum.GCC_VS;
} }
else if (dh.e_lfanew() == 0x78) {
offsetChoice = CompilerEnum.Clang;
}
else if (dh.e_lfanew() < 0x80) { else if (dh.e_lfanew() < 0x80) {
// 0x78 checked for Clang above, but 0x7c fits here too
offsetChoice = CompilerEnum.Unknown; offsetChoice = CompilerEnum.Unknown;
} }
else { else {
@@ -931,13 +940,13 @@ public class PeLoader extends AbstractPeDebugLoader {
asmChoice = CompilerEnum.BorlandUnk; asmChoice = CompilerEnum.BorlandUnk;
} }
else { else {
for (counter = 0; counter < asm16_GCC_VS.length; counter++) { for (counter = 0; counter < asm16_GCC_VS_Clang.length; counter++) {
if ((asm[counter] & 0xff) != (asm16_GCC_VS[counter] & 0xff)) { if ((asm[counter] & 0xff) != (asm16_GCC_VS_Clang[counter] & 0xff)) {
break; break;
} }
} }
if (counter == asm16_GCC_VS.length) { if (counter == asm16_GCC_VS_Clang.length) {
asmChoice = CompilerEnum.GCC_VS; asmChoice = CompilerEnum.GCC_VS_Clang;
} }
else { else {
asmChoice = CompilerEnum.Unknown; asmChoice = CompilerEnum.Unknown;
@@ -948,6 +957,7 @@ public class PeLoader extends AbstractPeDebugLoader {
for (int i = 10; i < asm.length - 3; i++) { for (int i = 10; i < asm.length - 3; i++) {
if (asm[i] == 'T' && asm[i + 1] == 'h' && asm[i + 2] == 'i' && asm[i + 3] == 's') { if (asm[i] == 'T' && asm[i + 1] == 'h' && asm[i + 2] == 'i' && asm[i + 3] == 's') {
errStringOffset = i; errStringOffset = i;
break;
} }
} }
@@ -966,6 +976,9 @@ public class PeLoader extends AbstractPeDebugLoader {
else if (compareBytesToChars(asm, errStringOffset, errString_GCC_VS)) { else if (compareBytesToChars(asm, errStringOffset, errString_GCC_VS)) {
errStringChoice = CompilerEnum.GCC_VS; errStringChoice = CompilerEnum.GCC_VS;
} }
else if (compareBytesToChars(asm, errStringOffset, errString_Clang)) {
errStringChoice = CompilerEnum.Clang;
}
else { else {
errStringChoice = CompilerEnum.Unknown; errStringChoice = CompilerEnum.Unknown;
} }
@@ -997,6 +1010,11 @@ public class PeLoader extends AbstractPeDebugLoader {
return compilerType; return compilerType;
} }
} }
else if ((offsetChoice == CompilerEnum.Clang ||
errStringChoice == CompilerEnum.Clang) && asmChoice == CompilerEnum.GCC_VS_Clang) {
compilerType = CompilerEnum.Clang;
return compilerType;
}
else if (errStringChoice == CompilerEnum.Unknown || asmChoice == CompilerEnum.Unknown) { else if (errStringChoice == CompilerEnum.Unknown || asmChoice == CompilerEnum.Unknown) {
compilerType = CompilerEnum.Unknown; compilerType = CompilerEnum.Unknown;
return compilerType; return compilerType;
@@ -17,11 +17,8 @@ package ghidra.app.cmd.data;
import ghidra.app.util.datatype.microsoft.DataValidationOptions; import ghidra.app.util.datatype.microsoft.DataValidationOptions;
import ghidra.app.util.datatype.microsoft.MSDataTypeUtils; import ghidra.app.util.datatype.microsoft.MSDataTypeUtils;
import ghidra.app.util.opinion.PeLoader;
import ghidra.app.util.opinion.PeLoader.CompilerOpinion.CompilerEnum;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.CompilerSpecID;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
@@ -113,17 +110,6 @@ public abstract class AbstractCreateDataTypeModel {
imageBaseAddress = getProgram().getImageBase(); imageBaseAddress = getProgram().getImageBase();
} }
/**
* Determine if the program in this model is for windows.
* @return true if the program is a windows program.
*/
final protected boolean isWindows() {
CompilerSpecID compilerSpecID = program.getCompilerSpec().getCompilerSpecID();
return compilerSpecID.getIdAsString().equals("windows") &&
program.getExecutableFormat().equals(PeLoader.PE_NAME) &&
program.getCompiler().equals(CompilerEnum.VisualStudio.toString());
}
/** /**
* Determine if the address for this model is actually in the program. * Determine if the address for this model is actually in the program.
* @return true if the address for the data type is valid. * @return true if the address for the data type is valid.
@@ -293,10 +279,6 @@ public abstract class AbstractCreateDataTypeModel {
* address. The message in the exception indicates why the model isn't valid. * address. The message in the exception indicates why the model isn't valid.
*/ */
private void doValidate() throws InvalidDataTypeException { private void doValidate() throws InvalidDataTypeException {
if (!isWindows()) {
throw new InvalidDataTypeException(
getName() + " data type model is only valid for Visual Studio windows PE.");
}
if (!isValidAddress()) { if (!isValidAddress()) {
throw new InvalidDataTypeException( throw new InvalidDataTypeException(
getName() + " data type isn't at a valid address " + getAddress() + "."); getName() + " data type isn't at a valid address " + getAddress() + ".");
@@ -24,12 +24,9 @@ import ghidra.app.services.*;
import ghidra.app.util.datatype.microsoft.DataApplyOptions; import ghidra.app.util.datatype.microsoft.DataApplyOptions;
import ghidra.app.util.datatype.microsoft.DataValidationOptions; import ghidra.app.util.datatype.microsoft.DataValidationOptions;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.PeLoader;
import ghidra.app.util.opinion.PeLoader.CompilerOpinion.CompilerEnum;
import ghidra.framework.cmd.Command; import ghidra.framework.cmd.Command;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.InvalidDataTypeException; import ghidra.program.model.data.InvalidDataTypeException;
import ghidra.program.model.lang.CompilerSpecID;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.util.ProgramMemoryUtil; import ghidra.program.util.ProgramMemoryUtil;
@@ -64,10 +61,7 @@ public class PEExceptionAnalyzer extends AbstractAnalyzer {
@Override @Override
public boolean canAnalyze(Program program) { public boolean canAnalyze(Program program) {
CompilerSpecID compilerSpecID = program.getCompilerSpec().getCompilerSpecID(); return PEUtil.canAnalyzePeVisualStudioOrClang(program);
return compilerSpecID.getIdAsString().equals("windows") &&
program.getExecutableFormat().equals(PeLoader.PE_NAME) &&
program.getCompiler().equals(CompilerEnum.VisualStudio.toString());
} }
@Override @Override
@@ -87,8 +81,8 @@ public class PEExceptionAnalyzer extends AbstractAnalyzer {
"[\\x20,\\x21,\\x22]\\x05\\x93[\\x19,\\x39,\\x59,\\x79,\\x99,\\xb9,\\xd9,\\xf9]"; "[\\x20,\\x21,\\x22]\\x05\\x93[\\x19,\\x39,\\x59,\\x79,\\x99,\\xb9,\\xd9,\\xf9]";
String bePattern = String bePattern =
"[\\x19,\\x39,\\x59,\\x79,\\x99,\\xb9,\\xd9,\\xf9]\\x93\\x05[\\x20,\\x21,\\x22]"; "[\\x19,\\x39,\\x59,\\x79,\\x99,\\xb9,\\xd9,\\xf9]\\x93\\x05[\\x20,\\x21,\\x22]";
RegExSearchData regExSearchData = RegExSearchData RegExSearchData regExSearchData = RegExSearchData.createRegExSearchData(
.createRegExSearchData(program.getLanguage().isBigEndian() ? bePattern : lePattern); program.getLanguage().isBigEndian() ? bePattern : lePattern);
int alignment = 4; int alignment = 4;
SearchInfo searchInfo = new SearchInfo(regExSearchData, MATCH_LIMIT, false, true, alignment, SearchInfo searchInfo = new SearchInfo(regExSearchData, MATCH_LIMIT, false, true, alignment,
false, new CodeUnitSearchInfo(false, true, true), null); false, new CodeUnitSearchInfo(false, true, true), null);
@@ -26,6 +26,7 @@ import ghidra.app.util.datatype.microsoft.GuidInfo;
import ghidra.app.util.datatype.microsoft.GuidUtil; import ghidra.app.util.datatype.microsoft.GuidUtil;
import ghidra.app.util.opinion.BinaryLoader; import ghidra.app.util.opinion.BinaryLoader;
import ghidra.app.util.opinion.PeLoader; import ghidra.app.util.opinion.PeLoader;
import ghidra.app.util.opinion.PeLoader.CompilerOpinion.CompilerEnum;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.data.TypeDef; import ghidra.program.model.data.TypeDef;
@@ -42,12 +43,11 @@ public class PEUtil {
return true; return true;
} }
if (format.equals(BinaryLoader.BINARY_NAME)) { if (format.equals(BinaryLoader.BINARY_NAME)) {
MemoryByteProvider mbp = MemoryByteProvider mbp = new MemoryByteProvider(program.getMemory(),
new MemoryByteProvider(program.getMemory(),
program.getAddressFactory().getDefaultAddressSpace()); program.getAddressFactory().getDefaultAddressSpace());
try { try {
FactoryBundledWithBinaryReader reader = FactoryBundledWithBinaryReader reader = new FactoryBundledWithBinaryReader(
new FactoryBundledWithBinaryReader(RethrowContinuesFactory.INSTANCE, mbp, true/*LittleEndian*/); RethrowContinuesFactory.INSTANCE, mbp, true/*LittleEndian*/);
DOSHeader dosHeader = DOSHeader.createDOSHeader(reader); DOSHeader dosHeader = DOSHeader.createDOSHeader(reader);
if (dosHeader.e_magic() == DOSHeader.IMAGE_DOS_SIGNATURE) { if (dosHeader.e_magic() == DOSHeader.IMAGE_DOS_SIGNATURE) {
int peHeaderStartIndex = dosHeader.e_lfanew(); int peHeaderStartIndex = dosHeader.e_lfanew();
@@ -63,6 +63,12 @@ public class PEUtil {
return false; return false;
} }
static public boolean canAnalyzePeVisualStudioOrClang(Program program) {
return program.getExecutableFormat().equals(PeLoader.PE_NAME) &&
(program.getCompiler().equals(CompilerEnum.VisualStudio.toString()) ||
program.getCompiler().equals(CompilerEnum.Clang.toString()));
}
static DataType getActualType(DataType dataType) { static DataType getActualType(DataType dataType) {
if (dataType instanceof TypeDef) { if (dataType instanceof TypeDef) {
return getActualType(((TypeDef) dataType).getDataType()); return getActualType(((TypeDef) dataType).getDataType());
@@ -76,8 +82,7 @@ public class PEUtil {
AddressSpace defaultSpace = addressFactory.getDefaultAddressSpace(); AddressSpace defaultSpace = addressFactory.getDefaultAddressSpace();
try { try {
int addrAsInt = memory.getInt(addr); int addrAsInt = memory.getInt(addr);
Address pointedToAddr = Address pointedToAddr = addressFactory.getAddress(defaultSpace.getSpaceID(), addrAsInt);
addressFactory.getAddress(defaultSpace.getSpaceID(), addrAsInt);
return memory.contains(pointedToAddr); return memory.contains(pointedToAddr);
} }
catch (MemoryAccessException e) { catch (MemoryAccessException e) {
@@ -91,8 +96,7 @@ public class PEUtil {
AddressSpace defaultSpace = addressFactory.getDefaultAddressSpace(); AddressSpace defaultSpace = addressFactory.getDefaultAddressSpace();
try { try {
int addrAsInt = memory.getInt(addr); int addrAsInt = memory.getInt(addr);
Address pointedToAddr = Address pointedToAddr = addressFactory.getAddress(defaultSpace.getSpaceID(), addrAsInt);
addressFactory.getAddress(defaultSpace.getSpaceID(), addrAsInt);
if (memory.contains(pointedToAddr)) { if (memory.contains(pointedToAddr)) {
GuidInfo guidInfo = GuidUtil.getKnownGuid(program, pointedToAddr); GuidInfo guidInfo = GuidUtil.getKnownGuid(program, pointedToAddr);
if (guidInfo != null) { if (guidInfo != null) {
@@ -69,7 +69,7 @@ public class RttiAnalyzer extends AbstractAnalyzer {
@Override @Override
public boolean canAnalyze(Program program) { public boolean canAnalyze(Program program) {
return PEUtil.canAnalyze(program); return PEUtil.canAnalyzePeVisualStudioOrClang(program);
} }
@Override @Override
@@ -134,7 +134,7 @@ public class RttiAnalyzer extends AbstractAnalyzer {
monitor.setMaximum(possibleRtti0Addresses.size()); monitor.setMaximum(possibleRtti0Addresses.size());
monitor.setMessage("Creating RTTI Data..."); monitor.setMessage("Creating RTTI Data...");
ArrayList<Address> rtti0Locations = new ArrayList<Address>(); ArrayList<Address> rtti0Locations = new ArrayList<>();
int count = 0; int count = 0;
for (Address rtti0Address : possibleRtti0Addresses) { for (Address rtti0Address : possibleRtti0Addresses) {
monitor.checkCanceled(); monitor.checkCanceled();
@@ -277,7 +277,7 @@ public class RttiAnalyzer extends AbstractAnalyzer {
} }
// Each time a match for this byte pattern validate as an RTTI4 and add to list // Each time a match for this byte pattern validate as an RTTI4 and add to list
GenericMatchAction<Address> action = new GenericMatchAction<Address>(rtti0Address) { GenericMatchAction<Address> action = new GenericMatchAction<>(rtti0Address) {
@Override @Override
public void apply(Program prog, Address addr, Match match) { public void apply(Program prog, Address addr, Match match) {
Address possibleRtti4Address; Address possibleRtti4Address;
@@ -311,7 +311,7 @@ public class RttiAnalyzer extends AbstractAnalyzer {
// create a Pattern of the bytes and the MatchAction to perform upon a match // create a Pattern of the bytes and the MatchAction to perform upon a match
GenericByteSequencePattern<Address> genericByteMatchPattern = GenericByteSequencePattern<Address> genericByteMatchPattern =
new GenericByteSequencePattern<Address>(bytes, action); new GenericByteSequencePattern<>(bytes, action);
searcher.addPattern(genericByteMatchPattern); searcher.addPattern(genericByteMatchPattern);
} }
@@ -512,7 +512,7 @@ public class RttiModelTest extends AbstractRttiTest {
} }
@Test @Test
public void testInvalidRtti4_64NonVS() throws Exception { public void testInvalidRtti4_UnalignedRtti0() throws Exception {
ProgramBuilder builder = build64BitX86NonVS(); ProgramBuilder builder = build64BitX86NonVS();
ProgramDB program = builder.getProgram(); ProgramDB program = builder.getProgram();
setupRtti4_32(builder, 0x101001340L, 0, 0, 0, "0x00005364", "0x0000137c"); setupRtti4_32(builder, 0x101001340L, 0, 0, 0, "0x00005364", "0x0000137c");
@@ -522,8 +522,7 @@ public class RttiModelTest extends AbstractRttiTest {
model.validate(); model.validate();
} }
catch (InvalidDataTypeException e) { catch (InvalidDataTypeException e) {
assertEquals( assertEquals("TypeDescriptor data type is not properly aligned at 101005364.",
"RTTICompleteObjectLocator data type model is only valid for Visual Studio windows PE.",
e.getMessage()); e.getMessage());
} }
} }
@@ -12,6 +12,7 @@
id="x86:LE:32:default"> id="x86:LE:32:default">
<description>Intel/AMD 32-bit x86</description> <description>Intel/AMD 32-bit x86</description>
<compiler name="Visual Studio" spec="x86win.cspec" id="windows"/> <compiler name="Visual Studio" spec="x86win.cspec" id="windows"/>
<compiler name="clang" spec="x86win.cspec" id="clangwindows"/>
<compiler name="gcc" spec="x86gcc.cspec" id="gcc"/> <compiler name="gcc" spec="x86gcc.cspec" id="gcc"/>
<compiler name="Borland C++" spec="x86borland.cspec" id="borlandcpp"/> <compiler name="Borland C++" spec="x86borland.cspec" id="borlandcpp"/>
<compiler name="Delphi" spec="x86delphi.cspec" id="borlanddelphi"/> <compiler name="Delphi" spec="x86delphi.cspec" id="borlanddelphi"/>
@@ -83,6 +84,7 @@
id="x86:LE:64:default"> id="x86:LE:64:default">
<description>Intel/AMD 64-bit x86</description> <description>Intel/AMD 64-bit x86</description>
<compiler name="Visual Studio" spec="x86-64-win.cspec" id="windows"/> <compiler name="Visual Studio" spec="x86-64-win.cspec" id="windows"/>
<compiler name="clang" spec="x86-64-win.cspec" id="clangwindows"/>
<compiler name="gcc" spec="x86-64-gcc.cspec" id="gcc"/> <compiler name="gcc" spec="x86-64-gcc.cspec" id="gcc"/>
<external_name tool="gnu" name="i386:x86-64:intel"/> <external_name tool="gnu" name="i386:x86-64:intel"/>
<external_name tool="IDA-PRO" name="metapc"/> <external_name tool="IDA-PRO" name="metapc"/>
@@ -6,6 +6,12 @@
<constraint primary="334" processor="x86" endian="little" size="32" /> <constraint primary="334" processor="x86" endian="little" size="32" />
<constraint primary="34404" processor="x86" endian="little" size="64" /> <constraint primary="34404" processor="x86" endian="little" size="64" />
</constraint> </constraint>
<constraint compilerSpecID="clangwindows">
<constraint primary="332" secondary="clang" processor="x86" endian="little" size="32" />
<constraint primary="333" secondary="clang" processor="x86" endian="little" size="32" />
<constraint primary="334" secondary="clang" processor="x86" endian="little" size="32" />
<constraint primary="34404" secondary="clang" processor="x86" endian="little" size="64" />
</constraint>
<constraint compilerSpecID="borlandcpp"> <constraint compilerSpecID="borlandcpp">
<constraint primary="332" secondary="borlandcpp" processor="x86" endian="little" size="32" /> <constraint primary="332" secondary="borlandcpp" processor="x86" endian="little" size="32" />
<constraint primary="333" secondary="borlandcpp" processor="x86" endian="little" size="32" /> <constraint primary="333" secondary="borlandcpp" processor="x86" endian="little" size="32" />